全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:4194
推到 Plurk!
推到 Facebook!

Erik's Open Tools API FAQ and Resources for D5/D6

 
axsoft
版主


發表:681
回覆:1056
積分:969
註冊:2002-03-13

發送簡訊給我
#1 引用回覆 回覆 發表時間:2003-01-14 10:29:00 IP:61.218.xxx.xxx 未訂閱

Erik's Open Tools API FAQ and Resources for Delphi5/6

資料來源:http://www.gexperts.org/contact.html If you have additions or corrections, please contact me. But, please do not send me questions about how to use the Open Tools API - instead, use the resources listed below. What is the Open Tools API? The Open Tools API (OTA) is a set of interfaces that allow developers to add features to the Delphi and C Builder IDEs. These additions are called wizards or experts. Wizards can use the OTA interfaces to modify the IDE, obtain information about the IDE's state, and receive notification of important events. To create wizards, you should first get the Professional or Enterprise edition of Delphi or C Builder, since these versions include the interface definitions in ToolsAPI.pas that will make your programming easier. Why isn't the Open Tools API documented by Borland? It is documented! Starting with C Builder 6 and Delphi 6, the OTA is fully documented. Open the *iota.hlp file and look at the index there for details. In the past, Borland has said that they want the freedom to change the Open Tools API interfaces as they need to, and that documentation would give users the impression that the interfaces will be stable. But, I think the real reason it is undocumented is that few people inside Borland use the interfaces and understand them fully. Also, the resources simply weren't previously available to draft the documentation. Where can I get help with my Open Tools API questions? \Source\ToolsApi\ToolsAPI.pas The best place to learn about the Open Tools API is is the ToolsAPI.pas unit itself. It is available in the Professional and Enterprise editions only. All of the interfaces are defined there, and many of them have comments about their purpose and usage. Newsgroup Search Engines There are several free web services that allow you to search for answers to previously asked questions in the Open Tools API newsgroup. I recommend you search at least one of these before posting, as it generally gives multiple answers to the most common questions. Try one of the following: Search Site Newsgroups Date Range Search Features Speed Google Groups All May 1981 - Now Good Fast Mers Borland May 1997 - Now Limited Slow Tamarack Associates Borland Oct. 1997 - Now Moderate Moderate Developers.href.com Many June 1997 - Now Moderate Moderate The Open Tools API Newsgroup Borland runs a newsgroup server that has an Open Tools API discussion group on it. Before posting, please read the newsgroup guidelines, and check the newsgroup search engines above and the previous messages in the group for answers to your questions. You can access the newsgroup at news://newsgroups.borland.com/borland.public.delphi.opentoolsapi Example Code Delphi Super Page (US Mirror) Torry's Delphi Pages (US Mirror) Other Web Sites Ray Lischner's Open Tools Resources - Ray is the author of the only book on the Open Tools API. It only covers the old-style Open Tools API for Delphi 2/3, but might still be useful. Open Tools Interfaces by Rappido - Descriptions of how to obtain a few of the interfaces. Open Tools Tutorial by Cyril J. Jandia - Covers packages, portability, window types, installation, custom modules, docking forms, module editors, sprigs, etc. OTA Help File by Pete Fraser - A limited help file that lists the OTA interfaces (still under construction) What is the "old" OTA and what is the "new" OTA? Which one should I use? This FAQ only covers the "new" Open Tools API (OTA), which consists only of the ToolsAPI.pas unit in Delphi 4 or greater, and C Builder 4 or greater. The older OTA is depreciated and should no longer be used except to maintain compatibility with older IDE versions. Support for the old OTA will likely be dropped in a future version of Delphi. The old Open Tools API consists of the following units: ExptIntf, FileIntf, IStreams, ToolIntf, VcsIntf, VirtIntf. Where can I get a simple wizard/expert to customize? Here is the Pascal source for the simplest "Hello World!" wizard using the Open Tools API. Just compile and install this package (DPK) into the IDE, and try out the new menu item on the Help menu. Can I create wizards in C Builder? Yes. The Open Tools API was originally designed with Delphi in mind, so wizards might be easier to create in Delphi, but C Builder works fine. Can I install a Delphi-created wizard into C Builder? Yes, GExperts is one example of an expert written in Delphi that can be compiled and installed into C Builder. Should I ever call Release on an interface obtained from the IDE? It is not necessary to call Release on an IDE interface obtained via the Open Tools API. The interfaces are reference counted for you, and the associated memory will be freed as soon as all interface references go out of scope. Note that you can force the IDE to release an interface by setting all references to nil. How can I add published properties to a TForm descendent? Add published properties to a regular TForm Add the form to the Object Repository (Project menu) Add the form to an existing design time package (such as Borland User Components) or to a new design-time package. Add DsgnIntf/DesignIntf to the implementation uses clause of some unit in the package, and add a register procedure as follows: procedure Register; begin RegisterCustomModule(TMyForm, TCustomModule); end; Finally, inherit from your form in the repository inside a project and the new published properties will show up. There is also a much more complex method involving writing a module creation expert, a repository expert, and using CreateModuleEx and different streams, but is much more error-prone and for most people, has no distinct advantages. Note that the IDE won't allow you to add both published properties and components to a custom module at the same time. The workaround is to create a form with your custom properties in a package, and then have a descendent form in the repository which adds the components you want there by default. How do I obtain the current project interface? You need to iterate through all of the modules to find the project group and then get that group's active project: // Modified from code posted by Ray Lischner (www.tempest-sw.com)
function GetCurrentProject: IOTAProject;
var
  Services: IOTAModuleServices;
  Module: IOTAModule;
  Project: IOTAProject;
  ProjectGroup: IOTAProjectGroup;
  MultipleProjects: Boolean;
  I: Integer;
begin
  Result := nil;
  MultipleProjects := False;
  Services := BorlandIDEServices as IOTAModuleServices;
  for I := 0 to Services.ModuleCount - 1 do
  begin
    Module := Services.Modules[I];
    if Module.QueryInterface(IOTAProjectGroup, ProjectGroup) = S_OK then
    begin
      Result := ProjectGroup.ActiveProject;
      Exit;
    end
    else if Module.QueryInterface(IOTAProject, Project) = S_OK then
    begin
      if Result = nil then
        // Found the first project, so save it
        Result := Project
      else
        MultipleProjects := True;
        // It doesn't look good, but keep searching for a project group
    end;
  end;
  if MultipleProjects then
    Result := nil;
end;
How do I obtain the current project group interface? You need to iterate through all of the modules to find the one that implements IOTAProjectGroup:
function GetCurrentProjectGroup: IOTAProjectGroup;
var
  IModuleServices: IOTAModuleServices;
  IModule: IOTAModule;
  IProjectGroup: IOTAProjectGroup;
  i: Integer;
begin
  Result := nil;
  IModuleServices := BorlandIDEServices as IOTAModuleServices;
  for i := 0 to IModuleServices.ModuleCount - 1 do
  begin
    IModule := IModuleServices.Modules[i];
    if IModule.QueryInterface(IOTAProjectGroup, IProjectGroup) = S_OK then
    begin
      Result := IProjectGroup;
      Break;
    end;
  end;
end;
How can I obtain the IOTAProjectResource interface for a given project?
function GetProjectResource(Project: IOTAProject): IOTAProjectResource;
var
  i: Integer;
  IEditor: IOTAEditor;
begin
  Result := nil;
  for i:= 0 to (Project.GetModuleFileCount - 1) do
  begin
    IEditor := Project.GetModuleFileEditor(i);
    if Supports(IEditor, IOTAProjectResource, Result) then
      Break;
  end;
end;
How can I get a list of all installed components? See IOTAPackageServices.GetComponentName in ToolsAPI.pas. Is there any OTA support for creating type libraries or controlling the type library editor? If you look at IOTATypeLibEditor and IOTATypeLibModule, you'll see there might be internal plans to add some support, but it isn't implemented yet. Is there any OTA support for parsing a source file or obtaining Code Insight information? This is a common request, but the Open Tools API does not expose unit structure details or Code Insight information such as method parameter lists, symbol declaration locations, class members, and symbol table information. As a result, you will need to parse the source yourself or use an existing language parser such as those at Torry's Delphi Pages (search for mwDelPar or mwPasPar). Should I compile my wizard as a DLL or a Package? Packages are easier to load and unload without restarting the IDE (and hence easier to debug), but they can create unit naming conflicts in the IDE. Conflicts happen when the name a wizard's unit matches the name of a unit in another loaded design-time package. In this case, both packages can not be loaded at the same time. The recommended workaround is to prefix all of your unit names with a "unique" prefix. GExperts, for example, uses "GX_" as the name prefix for its units. Why does my wizard have to dynamically link to the VCL/DesignIde packages? If you want access to a useful BorlandIDEServices global variable from ToolsAPI.pas, you must compile your wizard linking to the VCL (Delphi 4/5) or DesignIde (Delphi 6) package. See the Packages tab in the Project Options dialog for help on compiling with packages. How do I get a hold of the designer for a DataModule? The owner of the datamodule at design-time is a TCustomForm which has a Designer property. How do a I get a reference to an IOTAXxxx interface? In general, just search ToolsAPI.pas for a method that returns the interface type you are looking for. But, sometimes things are a little trickier, and you have to use QueryInterface or Supports to find what you want: Interface Obtained From INTAComponent IOTAComponent INTAFormEditor IOTAFormEditor IFormDesigner INTAFormEditor IOTAKeyboardDiagnostics BorlandIDEServices IOTAEditActions IOTAEditView How can I debug a DLL wizard? Exit your IDE Remove any registry entries which load the expert DLL into your IDE. Look in HKEY_CURRENT_USER\Software\Borland\Delphi\X.0\Experts. Start your IDE, and verify the expert is not loaded. Compile your expert DLL. In the project options, be sure to turn on debug information, stack frames, reference info, etc. Turn optimizations off. Re-register the DLL with the IDE by adding an entry to HKEY_CURRENT_USER\Software\Borland\Delphi\X.0\Experts. Select Run, Parameters from the IDE menu. Enter the IDE's executable as the host application for your DLL. Run the host application (F9), and another copy of your IDE should appear with the expert loaded. You can now debug the DLL as it were a normal program (watches, breakpoints, inspections, tooltip evaluation, etc.). Note that library debugging does not work well in Delphi 4 and BCB 4. Both will lockup fairly often when debugging DLLs and packages. Delphi 3, 5, and 6 are much more stable in this respect. How can I debug a package wizard? In the project options for your package, turn on debug information, stack frames, reference info, etc. Turn optimizations off. Uncheck your package in the Project Options Packages tab, if necessary. Build your package (don't install it). Select Run, Parameters from the IDE menu. Enter the IDE's executable as the host application for your package. Run the host application (F9), and another copy of your IDE should appear. In the second copy of the IDE, open up the Project Options and load your expert package into the IDE. You can now debug the package as it were a normal program (watches, breakpoints, inspections, tooltip evaluation, etc.). Note that library debugging does not work well in Delphi 4 and BCB 4. Both will lockup fairly often when debugging DLLs and packages. Delphi 3, 5, and 6 are much more stable in this respect. How do I implement a form notifier (IOTAFormNotifier)? Declare something like this:
TMyFormNotifier = class(TNotifierObject, IOTANotifier, IOTAFormNotifier)
protected
  procedure FormActivated;
  procedure FormSaving;
  procedure ComponentRenamed(ComponentHandle: TOTAHandle;
      const OldName, NewName: string);
end;
Implement all of the above methods, even if they are blank. Finally, add your notifier using IOTAModule.GetModuleFileEditor(0).AddNotifier. In Delphi 5, form notifiers won't actually fire notifications for BeforeSave or AfterSave (use a module notifier for this). It should fire the notifications in the declaration above, as well as Destroyed and Modified from IOTANotifier. How do I implement an IDE notifier (IOTAIDENotifier)? Create an object that implements all of the IOTAIDENotifier and descendent interface methods. Then register the notifier using IOTAServices.AddNotifier and watch for notifications from the IDE. Be sure to call IOTAServices.RemoveNotifier when you are done. Here is a Delphi 5/6 example IOTAIDENotifier.
unit IdeNotifier;
interface
procedure Register;
implementation
uses SysUtils, TypInfo, ToolsApi;
var
  NotifierIndex: Integer;
type
  TIdeNotifier = class(TNotifierObject, IOTANotifier, IOTAIDENotifier)
  protected
    procedure AfterCompile(Succeeded: Boolean);
    procedure BeforeCompile(const Project: IOTAProject; var Cancel: Boolean);
    procedure FileNotification(NotifyCode: TOTAFileNotification;
      const FileName: string; var Cancel: Boolean);
  end;
procedure Register;
var
  Services: IOTAServices;
begin
  Services := BorlandIDEServices as IOTAServices;
  Assert(Assigned(Services), 'IOTAServices not available');
  NotifierIndex := Services.AddNotifier(TIdeNotifier.Create);
end;
procedure RemoveNotifier;
var
  Services: IOTAServices;
begin
  if NotifierIndex <> -1 then
  begin
    Services := BorlandIDEServices as IOTAServices;
    Assert(Assigned(Services), 'IOTAServices not available');
    Services.RemoveNotifier(NotifierIndex);
  end;
end;
function MsgServices: IOTAMessageServices;
begin
  Result := (BorlandIDEServices as IOTAMessageServices);
  Assert(Result <> nil, 'IOTAMessageServices not available');
end;
procedure TIdeNotifier.AfterCompile(Succeeded: Boolean);
begin
  MsgServices.AddTitleMessage('After Compile');
end;
procedure TIdeNotifier.BeforeCompile(const Project: IOTAProject; var Cancel: Boolean);
begin
  MsgServices.AddTitleMessage('Before Compile');
end;
procedure TIdeNotifier.FileNotification(NotifyCode: TOTAFileNotification;
  const FileName: string; var Cancel: Boolean);
begin
  MsgServices.AddTitleMessage(Format('%s: %s',
    [GetEnumName(TypeInfo(TOTAFIleNotification), Ord(NotifyCode)), FileName]));
end;
initialization
finalization
  RemoveNotifier;
end.
How can I get notified when a source file has changed? Don't use IOTAEditorNotifier since, surprisingly, it never fires in Delphi 4/5. Instead, attach a module notifier using IOTAModule.AddNotifier and watch for IOTAModuleNotifier.Modified. In Delphi 6, IOTAEditorNotifier works as expected. How can I add a menu item to the IDE's main menu? Use INTAServices.GetMainMenu to obtain a reference to the IDE's TMainMenu component. Iterate through all of the top-level menu items and find the parent menu item you want to add a menu item to. Then, use MyMenuItem.Insert() to add the menu item. GExperts has an IDE menu item expert that shows all IDE main menu items and their names. You may also find this tutorial by Miha Remec useful. How can I keep my wizard's menu item shortcuts from disappearing? In Delphi 5/6, you should register a shortcut for your menu item using the keybinding interfaces. First, implement a btPartial type keyboard binding via IOTAKeyboardBinding. In the BindKeyboard callback, use the passed in IOTAKeyBindingServices reference to call AddKeyBinding for each menu item, passing in the menu item's name as the last parameter (the ill named "HotKey" in Delphi 5): AddKeyBinding([ShortCut(Ord('G'), [ssCtrl])], FCallback, nil, 0, '', 'MenuItem1'); In Delphi 4, you will need to wait a few seconds after the IDE starts and set the menu item's ShortCut property. A timer works well to create the delay. How can I paint the palette bitmap for a specific component? You need to use the LibIntf unit, which is unsupported and undocumented, but try: LibIntf.DelphiIDE.GetPaletteItem(GetClass('TButton')).Paint How do I implement a module creator (IOTAModuleCreator)? Descend from TInterfacedObject and implement all of the methods in IOTACreator and IOTAModuleCreator as follows: TGxModuleCreator = class(TInterfacedObject, IOTACreator, IOTAModuleCreator) Here is sample code for a Delphi 5/6 module creator that resides in the repository.
    unit GXModuleCreator;    interface    procedure Register;    implementation    uses SysUtils, Windows,
  {$IFDEF VER130} // Delphi 5
  DsgnIntf,
  {$ELSE not VER_140} // Delphi 6 
  DesignIntf,
  {$ENDIF}
  ToolsApi, Dialogs;    type
  TGxModuleCreatorWizard = class(TNotifierObject, IOTAWizard, IOTARepositoryWizard, IOTAFormWizard)
  public
    // IOTAWizard
    function GetIDString: string;
    function GetName: string;
    function GetState: TWizardState;
    procedure Execute;
    // IOTARepositoryWizard
    function GetAuthor: string;
    function GetComment: string;
    function GetPage: string;
    {$IFDEF VER130} // Delphi 5
    function GetGlyph: HICON;
    {$ELSE not VER_140} // Delphi 6 
    function GetGlyph: Cardinal;
    {$ENDIF}
  end;      TGxModuleCreator = class(TInterfacedObject, IOTACreator, IOTAModuleCreator)
  public
    // IOTACreator
    function GetCreatorType: string;
    function GetExisting: Boolean;
    function GetFileSystem: string;
    function GetOwner: IOTAModule;
    function GetUnnamed: Boolean;
    // IOTAModuleCreator
    function GetAncestorName: string;
    function GetImplFileName: string;
    function GetIntfFileName: string;
    function GetFormName: string;
    function GetMainForm: Boolean;
    function GetShowForm: Boolean;
    function GetShowSource: Boolean;
    function NewFormFile(const FormIdent, AncestorIdent: string): IOTAFile;
    function NewImplSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile;
    function NewIntfSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile;
    procedure FormCreated(const FormEditor: IOTAFormEditor);
  end;      TGxSourceFile = class(TInterfacedObject, IOTAFile)
  private
    FSource: string;
  public
    function GetSource: string;
    function GetAge: TDateTime;
    constructor Create(const Source: string);
  end;    procedure Register;
begin
  RegisterPackageWizard(TGxModuleCreatorWizard.Create);
end;    { TGxModuleCreatorWizard }    procedure TGxModuleCreatorWizard.Execute;
begin
  (BorlandIDEServices as IOTAModuleServices).CreateModule(TGxModuleCreator.Create);
end;    function TGxModuleCreatorWizard.GetAuthor: string;
begin
  Result := 'Erik.Berry';
end;    function TGxModuleCreatorWizard.GetComment: string;
begin
  Result := 'GX Module Creator';
end;    {$IFDEF VER130} // Delphi 5
function TGxModuleCreatorWizard.GetGlyph: HICON;
{$ELSE not VER_140} // Delphi 6 
function TGxModuleCreatorWizard.GetGlyph: Cardinal;
{$ENDIF}
begin
  Result := 0;
end;    function TGxModuleCreatorWizard.GetIDString: string;
begin
  Result := 'EB.GXModuleCreatorWizard';
end;    function TGxModuleCreatorWizard.GetName: string;
begin
  Result := 'GX ModuleCreator';
end;    function TGxModuleCreatorWizard.GetPage: string;
begin
  Result := 'New';
end;    function TGxModuleCreatorWizard.GetState: TWizardState;
begin
  Result := [wsEnabled];
end;    { TGxModuleCreator }    procedure TGxModuleCreator.FormCreated(const FormEditor: IOTAFormEditor);
begin
  // Nothing
end;    function TGxModuleCreator.GetAncestorName: string;
begin
  Result := 'Form';
end;    function TGxModuleCreator.GetCreatorType: string;
begin
  // Return sUnit or sText as appropriate
  Result := sForm;
end;    function TGxModuleCreator.GetExisting: Boolean;
begin
  Result := False;
end;    function TGxModuleCreator.GetFileSystem: string;
begin
  Result := '';
end;    function TGxModuleCreator.GetFormName: string;
begin
  Result := '';
end;    function TGxModuleCreator.GetImplFileName: string;
begin
  Result := '';
end;    function TGxModuleCreator.GetIntfFileName: string;
begin
  Result := '';
end;    function TGxModuleCreator.GetMainForm: Boolean;
begin
  Result := False;
end;    function TGxModuleCreator.GetOwner: IOTAModule;
var
  ModuleServices: IOTAModuleServices;
  Module: IOTAModule;
  NewModule: IOTAModule;
begin
  // You may prefer to return the project group's ActiveProject instead
  Result := nil;
  ModuleServices := (BorlandIDEServices as IOTAModuleServices);
  Module := ModuleServices.CurrentModule;      if Module <> nil then
  begin
    if Module.QueryInterface(IOTAProject, NewModule) = S_OK then
      Result := NewModule        {$IFDEF VER130} // Delphi 5
    else if Module.GetOwnerCount > 0 then
    begin
      NewModule := Module.GetOwner(0);
    {$ELSE not VER_140} // Delphi 6 
    else if Module.OwnerModuleCount > 0 then
    begin
      NewModule := Module.OwnerModules[0];
    {$ENDIF}
      if NewModule <> nil then
        if NewModule.QueryInterface(IOTAProject, Result) <> S_OK then
          Result := nil;
    end;
  end;
end;    function TGxModuleCreator.GetShowForm: Boolean;
begin
  Result := True;
end;    function TGxModuleCreator.GetShowSource: Boolean;
begin
  Result := True;
end;    function TGxModuleCreator.GetUnnamed: Boolean;
begin
  Result := True;
end;    function TGxModuleCreator.NewFormFile(const FormIdent, AncestorIdent: string): IOTAFile;
begin
  Result := nil;
end;    function TGxModuleCreator.NewImplSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile;
const
  sSource =
  'unit %s;'   #13#10  
  '// Created with TGxModuleCreator'   #13#10  
  ''   #13#10  
  'interface'   #13#10  
  ''   #13#10  
  'uses'   #13#10  
  '  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;'   #13#10  
  ''   #13#10  
  'type'   #13#10  
  '  T%s = class(T%s)'   #13#10  
  '  private'   #13#10  
  '    { Private declarations }'   #13#10  
  '  public'   #13#10  
  '    { Public declarations }'   #13#10  
  '  end;'   #13#10  
  ''   #13#10  
  'var'   #13#10  
  '  %s: T%s;'   #13#10  
  ''   #13#10  
  'implementation'   #13#10  
  ''   #13#10  
  '{$R *.DFM}'   #13#10  
  ''   #13#10  
  'end.';
begin
  Result := TGxSourceFile.Create(Format(sSource, [ModuleIdent, FormIdent,
                           AncestorIdent, FormIdent, FormIdent]));
  // or Result := nil; for the default unit
end;    function TGxModuleCreator.NewIntfSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile;
begin
  Result := nil;
end;    { TGxSourceFile }    constructor TGxSourceFile.Create(const Source: string);
begin
  FSource := Source;
end;    function TGxSourceFile.GetAge: TDateTime;
begin
  Result := -1;
end;    function TGxSourceFile.GetSource: string;
begin
  Result := FSource;
end;    end.    
How do I implement a project creator (IOTAProjectCreator)? Descend from TInterfacedObject and implement all of the methods in IOTACreator and IOTAProjectCreator as follows: TGxProjectCreator = class(TInterfacedObject, IOTACreator, IOTAProjectCreator) Here is sample code for a project creator that installs itself into the Help menu.
unit ProjectCreator;    interface    procedure Register;    implementation    uses Windows, ToolsApi;    type
  TProjectWizard = class(TNotifierObject, IOTAMenuWizard, IOTAWizard)
  public
    procedure Execute;
    function GetIDString: string;
    function GetMenuText: string;
    function GetName: string;
    function GetState: TWizardState;
  end;      TGxProjectCreator = class(TInterfacedObject, IOTACreator, IOTAProjectCreator)
  public
    // IOTACreator
    function GetCreatorType: string;
    function GetExisting: Boolean;
    function GetFileSystem: string;
    function GetOwner: IOTAModule;
    function GetUnnamed: Boolean;
    // IOTAProjectCreator
    function GetFileName: string;
    function GetOptionFileName: string;
    function GetShowSource: Boolean;
    procedure NewDefaultModule;
    function NewOptionSource(const ProjectName: string): IOTAFile;
    procedure NewProjectResource(const Project: IOTAProject);
    function NewProjectSource(const ProjectName: string): IOTAFile;
  end;    procedure Register;
begin
  RegisterPackageWizard(TProjectWizard.Create);
end;    procedure TProjectWizard.Execute;
begin
  (BorlandIDEServices as IOTAModuleServices).CreateModule(TGxProjectCreator.Create);
end;    function TProjectWizard.GetIDString: string;
begin
  Result := 'GX.ProjectCreator';
end;    function TProjectWizard.GetMenuText: string;
begin
  Result := '&GX Project Creator';
end;    function TProjectWizard.GetName: string;
begin
  Result := 'GX Project Creator';
end;    function TProjectWizard.GetState: TWizardState;
begin
  Result := [wsEnabled];
end;    { TGxProjectCreator }    function TGxProjectCreator.GetCreatorType: string;
begin
  Result := sApplication; // Create an application project
end;    function TGxProjectCreator.GetExisting: Boolean;
begin
  Result := False; // Create a new project
end;    function TGxProjectCreator.GetFileName: string;
begin
  Result := ''; // Default
end;    function TGxProjectCreator.GetFileSystem: string;
begin
  Result := ''; // Default
end;    function TGxProjectCreator.GetOptionFileName: string;
begin
  Result := ''; // Default
end;    function GetCurrentProjectGroup: IOTAProjectGroup;
var
  IModuleServices: IOTAModuleServices;
  IModule: IOTAModule;
  IProjectGroup: IOTAProjectGroup;
  i: Integer;
begin
  Result := nil;
  IModuleServices := BorlandIDEServices as IOTAModuleServices;
  for i := 0 to IModuleServices.ModuleCount - 1 do
  begin
    IModule := IModuleServices.Modules[i];
    if IModule.QueryInterface(IOTAProjectGroup, IProjectGroup) = S_OK then
    begin
      Result := IProjectGroup;
      Break;
    end;
  end;
end;    function TGxProjectCreator.GetOwner: IOTAModule;
begin
  Result := GetCurrentProjectGroup;  // Owned by current project group
end;    function TGxProjectCreator.GetShowSource: Boolean;
begin
  Result := True; // Show the source in the editor
end;    function TGxProjectCreator.GetUnnamed: Boolean;
begin
  Result := True; // Project needs to be named/saved
end;    procedure TGxProjectCreator.NewDefaultModule;
begin
  // No default modules are created
end;    function TGxProjectCreator.NewOptionSource(const ProjectName: string): IOTAFile;
begin
  Result := nil; // For BCB only
end;    procedure TGxProjectCreator.NewProjectResource(const Project: IOTAProject);
begin
  // No resources needed
end;    function TGxProjectCreator.NewProjectSource(const ProjectName: string): IOTAFile;
begin
  // Create the default source code for a new application
  Result := nil;
end;    end.
How can I add menu items to the code editor's popup menu? IOTAEditView.GetEditWindow.Form.FindComponent('EditorLocalMenu') will return the editor's TPopupMenu component that you can add to. Your added menu items will work best if you add them to the end of the popup menu and may not work at all if you associate an action with them. Note that you might want an IOTAEditorNotifier to determine when to add your new menu items to new editor windows. How can I iterate over all units/forms in a project? IOTAProject.ModuleCount can be used to iterate over all modules, and IOTAProject.GetModule returns a reference to IOTAModuleInfo which gives you the FileName, FormName, etc. How can I publish a property of type T[Custom]Form? It doesn't work very well, but you can try to publish the property normally. The problem is that only currently created forms will be shown in the property editor, and storing an internal reference to one of those forms will often cause AVs when the target form is later closed. As a workaround, you can create a custom property editor that uses IOTAProject as above to get the class names of all forms in the project and insert them into the dropdown list for the property editor. Then store the form reference internally as a class name string, and use something like GetClass and RegisterClass to map a class name to a class type. With the class type, you can create the form at runtime. If you are sure your target form will always exist at runtime, another option to map from classes to instances is to search the Screen.Forms array. How can I obtain the currently active form editor (IOTAFormEditor)?
function GetActiveFormEditor: IOTAFormEditor;
var
  Module: IOTAModule;
  Editor: IOTAEditor;
  i: Integer;
begin
  Result := nil;
  Module := (BorlandIDEServices as IOTAModuleServices).CurrentModule;
  if Module <> nil then
  begin
    for i := 0 to Module.GetModuleFileCount - 1 do
    begin
      Editor := Module.GetModuleFileEditor(i);
      Editor.QueryInterface(IOTAFormEditor, Result);
      if Result <> nil then
        Break;
    end;
  end;
end;    How can I obtain the current form designer interface (IFormDesigner)?
function GetActiveFormDesigner: IFormDesigner;
var
  FormEditor: IOTAFormEditor;
begin
  Result := nil;
  FormEditor := GetActiveFormEditor;
  if FormEditor <> nil then
    Result := (FormEditor as INTAFormEditor).FormDesigner;
end;
How can I get a form editor from a module interface? You should iterate through all of the ModuleFileEditors, to see which one implements IOTAFormEditor:
function GetFormEditorFromModule(IModule: IOTAModule): IOTAFormEditor;
var
  i: Integer;
  IEditor: IOTAEditor;
begin
  Result := nil;
  if IModule = nil then
     Exit;
  for i := 0 to IModule.GetModuleFileCount - 1 do
  begin
    IEditor := IModule.GetModuleFileEditor(i);
    if Supports(IEditor, IOTAFormEditor, Result) then
      Break;
  end;
end;
Is there a way to determine if the user is editing a form or working in the code editor? You can't do this using only the new Open Tools API in Delphi 5, but you can use the old API to get this information from ToolServices.GetCurrentFile. Starting with Delphi 6, there is IOTAModule.GetCurrentEditor for this purpose. If you find these methods don't work for .h files in C Builder try IOTAEditorServices.TopBuffer.FileName. How can I tell when a module was removed from a project? The old OTA had an fnRemovedFromProject notification flag, but this doesn't exist in the new OTA. As a workaround, you can watch for changes to the project file using an IOTAEditorNotifier and the iterate over all modules to see which one might have been deleted, if any. How can I obtain the Name pro
系統時間:2024-11-23 20:29:03
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!