Delphi SDK How-to FAQ

 

Browse through frequently asked questions relevant to coding Altium Designer's SDK.

For more detailed information on the SDK API, refer to the Altium Designer SDK Reference.

System

What are the System Requirements for the Altium Designer SDK?

To develop software Extensions for Altium Designer using the Altium SDK, you need to have Embarcadero Delphi XE2 or later, the SDK and Altium Designer 13 or later. You can use any recent Delphi edition to build Altium Designer software Extensions; Embarcadero Delphi Starter edition (a low cost option), Professional edition, Enterprise, Architect and the Ultimate edition all work fine with the Altium SDK.

The Altium Designer SDK itself is composed of three main APIs; the DXP – a set of Electronic Data Platform API units, the PCB Editor API and the Schematic API. Note, each API has a set of source code units in Delphi / Object Pascal. Note that C++ and C# versions of the Altium SDK are also available.

Permissions

With the standard Altium SDK installation on Windows 7, the Embarcadero Delphi application may not be able to write directly to the SDK’s \Examples folder, or to Altium Designer's \System folder. The system's default Folder/User Permissions are the issue.

Windows' folder and user permissions could be modified to suit, but the simplest way to work around this is to manually copy the created DLLs and drop them in Altium Designer’s System folder, along with the extension project's configuration files, such as INS and RCS files. See the Setting up your Server Project section in the Getting started: Building a Delphi extension document for more information.

DXP Platform

Can I save a Schematic document in another file format using SDK?

Yes. The available document formats are: Ascii, Orcad, Template, Binary, standard schematic binary, AutoCad DXF and AutoCad DWG for schematic documents. Note that the three strings, Template, Binary and a blank string ""  represent the same Altium Designer Schematic Design format.

Code snippet:

doc := Client.GetDocumentByPath(ProjectDoc.DM_FullPath);
doc.SetModified(TRUE);
doc.DoFileSave(documentKind);

To save the document into another format, you need to set the documentKind parameter to one of the following format strings:

'ASCII'          – ASCII format
'ORCAD'          – ORCAD format
'TEMPLATE'
'BINARY'         – standard binary format
'AUTOCAD DXF'    – DXF format
'AUTOCAD DWG'    – DWG format

Is it possible to determine if the project is compiled and whether the compilation is up to date?

For many operations the project needs to be compiled. Without knowing if the project is compiled and wasn’t modified since then, all you can do is compile the project blindly each time before accessing the data. There is a way to avoid this unnecessary compilation.

You can use the DM_NeedsCompile method from the IProject object interface (EDPInterfaces unit) to determine whether the project needs compiling.

The declaration of this function from the IProject interface is: Function IProject.DM_NeedsCompile : LongBool;

Can a server module only be created in the PluginFactory function (as in the SDK samples)?

Is there is any other way? When does Altium Designer call the PluginFactory function? During launch or during a plugin command call from the Altium plugin panel?

You can create your server module anywhere, for example during loading the DLL module (in the Initialization clause).

The Altium Designer application calls the PluginFactory function right after loading the Dynamic Linked Library file (DLL). In this case the PluginFactory function in the Main unit is the best place for creating your server module.

Usually Altium Designer loads a specified server module (calls the PluginFactory function) when it has to launch a command related to this server module. But you can set the "SystemExtension = True" clause in your extension server installation file within the Server End block. In this case, Altium Designer will load your server module on startup automatically.

Server
    EditorName        = ...
        ...
    SystemExtension   = True
End

Can projects from older versions be updated to Altium Designer 13.1?

All of the compatibility issues are concerned with the main unit of a server project prior to Altium Designer, such as DXP Service Pack 2. Certain keywords such as stdcall, NewDocumentInstance, AddCommand methods all need replacing.

The main unit of the server project needs revising with the following items:

  • Replace AddCommand procedure with RegisterCommand procedure
  • Comments: Replace AddCommand method with RegisterCommand for the CommandLauncher as an aggregate class of the TServerModule class. The AddCommand method doesn't exist in Altium Designer. Use the RegisterCommand method instead to store a declared command (process) in the server table in Altium Designer.
  • Replace Stdcall with SafeCall;
  • Comments: This safecall keyword is used in the COM world and is better protected against failures of importing functions across a boundary such as an EXE to a DLL.
  • Replace PChar with WideString methods.
  • Comments: The NewDocumentInstance method of a TServerModule has its parameter signature changed slightly – replace PChars with WideStrings.

How do I execute other processes from my extension?

The MessageRouter_SendCommandToModule function in EDPUtil unit, allows your extension server to run a process from other server. The parameters for this function are Process, Parameters, EditorWindow.

The target window handle specifies the window handle of the target document object for the process to run on. If there is no document supported by the server this parameter should be set to Nil. This function automatically starts the target server if the server is not already started.

Processes can return results using the Parameters parameter. For example the "Client:RunCommonDialog" process runs a dialog and then returns the result through this parameter.

Example of invoking a Schematic’s Zoom Process:

Procedure ZoomToDoc;
Var
    Parameters : WideString;
Begin
  SetState_Parameter(Parameters, 'Action', 'Document');
  MessageRouter_SendCommandToModule('SCH:Zoom', Parameters, MessageRouter_GetState_CurrentEditorWindow);
End;

The string 'Action=Document' is assigned to the Parameters parameter and then it is passed in the process string SCH:Zoom and the zoom command is executed on a current schematic document.

A PCB example:

CommandLauncher.LaunchCommand('PCB:Zoom', 'Action=Redraw', Client.CurrentView); 

How do I add a new Delphi form into my extension Project?

By default, Delphi automatically creates the application's main form in memory by including the following code in the application's project source unit: Application.Create(TForm1,Form1);

These projects are compiled as EXE (executable) files. However server projects are complied as DLLs files thus, the main forms are not auto created at run time. You will have to create the forms dynamically. The procedure to attach a dialog form to your server project is as follows:

  1. Click File » New » VCL form from Delphi and a form is then generated in your server library module (in the project file), and adds the Form clause in the library source's Uses clause.
  2. Make sure the unit associated with the new form is in focus. Add the appropriate Altium Designer APIs, for example EDPClasses to the Uses directive for this new unit.
  3. The next step is to create the dialog at run time (whenever a process is invoked and display the dialog). The processes defined in the commands.pas unit of a server project is the starting point, and inside each process could lead to a function being called from another unit part of this server project. You need to implement the following code snippet to activate the form.

Creation of a dialog example in the commands.pas unit

Procedure Command_ProcessA(View : IServerDocumentView; Parameters : WideString);
Begin
    MyDialog := TMyDialog.Create(Application);
    MyDialog.ShowModal;
    MyDialog.Free;
End;

To obtain the application handle of Altium Designer so that the dialog's owner handle belongs to Altium Designer, you would need to set the Client.ApplicationHandle to the Application.Handle in the ServerFactory function in the main unit of the server project. This dialog will thus adopt Altium Designer's icon and only one same icon appears on the tasking bar.

The PlugInFactory function example:

Function PlugInFactory (AClient : IClient) : IServerModule;
Begin
    Result := TCustomizedServerModule.Create(AClient, 'CustomServer');
    Application.Handle := Client.ApplicationHandle;
End;

How do I open a document using a specific path?

Use the OpenDocument and ShowDocument methods of the IClient interface, or the DM_GetDocumentFromPath method from the IWorkspace interface (from the EDPInterfaces unit)

Code snippet:

_Client := Client;
If _Client = Nil Then Exit;
Kind := Client.GetDocumentKindFromDocumentPath(FileName);
ServerDocument := Client.OpenDocument(Kind,FileName);
If ServerDocument <> Nil Then
 Client.ShowDocument(ServerDocument)

Code snippet:

WorkSpace := GetWorkspace; //IWorkSpace interface
If WorkSpace = Nil then Exit;
//FullPath is a string containing the full path to the document.
Document := WorkSpace.DM_GetDocumentFromPath(FullPath); //IDocument interface
Kind := Client.GetDocumentKindFromDocumentPath(FileName);
ServerDocument := Client.OpenDocument(Kind,FileName);
If ServerDocument <> Nil Then
 Client.ShowDocument(ServerDocument)

How do I close a document in Altium Designer programmatically?

Use the CloseDocument method from the IClient interface. You need to pass in the document parameter of a IServerDocument type.

Code snippet:

_Client := Client;
If _Client = Nil Then Exit;
//ADocument is of IServerDocument type.
_Client.CloseDocument(ADocument);

How do I fetch an active Document?

To fetch an active document of a loaded project in Altium Designer, you need to use the DM_FocusedDocument method from the IWorkSpace interface (EDPInterfaces unit).

Code snippet:

WorkSpace := GetWorkspace; //IWorkSpace interface
If WorkSpace = Nil then Exit;
Document := WorkSpace.DM_FocusedDocument; //IDocument interface

How do I set my document to be the focused or active document?

Use the SetFocus method from the IServerDocumentView interface (EDPInterfaces unit) or Focus method from the IServerDocument interface.

Note that a document (of IServerDocument type) can have several document views, and in this case, the IServerDocument has a View property which is an indexed list of IServerDocumentViews. You will need to iterate to get the specific document view before you can apply the SetFocus method.

Code snippet:

WorkSpace := GetWorkspace; //IWorkSpace interface
If WorkSpace = Nil then Exit;
Document := WorkSpace.DM_FocusedDocument; //Grab the focused IDocument object
Document.Focus; // focus this document.

How do I check the active Document’s type (document kind)?

Use the Client object and invoke the currentView method to get the document type (kind) for the active document (from EDPClasses Unit).

Code snippet 1 – Using the Client interface:

_Client := Client;
If _Client = Nil Then Exit;
//Check if a schematic document exists or not.
CurrentView := _Client.CurrentView; // IServerDocumentView
OwnerDocument := CurrentView.OwnerDocument; // IServerDocument
If OwnerDocument.Kind = 'SCH' Then ShowMessage('A Schematic document');

OR

Code snippet 2 – Using the Workspace interface:

WorkSpace := GetWorkspace; //IWorkSpace interface
If WorkSpace = Nil then Exit;
Doc := WorkSpace.DM_FocusedDocument;
If Doc.DM_DocumentKind = 'SCH' Then ShowMessage('A Schematic document');

How do I get the active Project?

You need the workspace object first, and then invoke the DM_FocusedProject method to get the active project. The GetWorkspace function is from the EDPUtil unit. The IWorkspace interface is from the EDPInterfaces unit.

Code snippet:

WorkSpace := GetWorkspace; //workspace is a IWorkSpace interface
If WorkSpace = Nil then Exit;
FocusedProject := WorkSpace.DM_FocusedProject; //FocusedProject = IProject interface

How do I iterate documents in active Project?

You need the DM_FocusedProject method from the IWorkspace interface (from the EDPInterfaces Unit ) to fetch the active / focused project.

Code snippet:

WorkSpace := GetWorkspace; //IWorkSpace interface
If WorkSpace = Nil then Exit;
Project := WorkSpace.DM_FocusedProject; //IProject interface
For K := 0 To Project.DM_PhysicalDocumentCount – 1 Do
Begin
    Document := Project.DM_PhysicalDocuments(K);
    S := Document.DM_FullPath; //s is the full filename of the document.
End;

How do I iterate logical documents of a Project?

You need the DM_LogicalDocuments method from the IProject interface (from EDPInterfaces unit) to look for logical documents of a project.

Code snippet:

WorkSpace := GetWorkspace; //IWorkSpace interface
If WorkSpace = Nil then Exit;
Project := WorkSpace.DM_FocusedProject; //IProject interface
For K := 0 To Project.DM_LogicalDocumentCount – 1 Do
Begin
    LogicalDocument := Project.DM_LogicalDocuments(K); //IDocument
End;

How do I add/delete a document to/from a Project?

Workspace manager functions:

  • DM_AddSourceDocument
  • DM_RemoveSourceDocument

How do I compile a Project in Altium Designer?

Use the DM_Compile method from the IProject interface to do a compile of a project.

Code snippet:

WorkSpace := GetWorkspace;    If WorkSpace = Nil then Exit;
Project := WorkSpace.DM_FocusedProject;
  If Project = Nil Then Exit;
  If Project.DM_NeedsCompile Then
    Project.DM_Compile;

Output Jobs

How can I configure and execute outputs in OutputJob documents?

To get the OutputJob documents from the project you need to iterate all logical documents and find the document containing DocumentKind equal to "OUTPUTJOB".

Follow these steps to execute OutputJob from the SDK:

  1. Find OutputJob file in the project (iterating through the logical documents).
  2. Open this file and make it active.
  3. Run the command depending on the "output container" you want to use.
Procedure Command_PrintOutputJobPDF(View : IServerDocumentView; Parameters : WideString);
Var
    WorkSpace  : IWorkspace;
    Project    : IProject;
    FileName   : String;
    Process    : String;
    ProjectDoc : IDocument;
    ServerDoc  : IServerDocument;
    i          : Integer;
Begin
    WorkSpace := GetWorkspace;
    If WorkSpace = Nil then
        Exit;
    Project := WorkSpace.DM_FocusedProject;
    If Project = Nil Then
        Exit;
    If Project.DM_NeedsCompile Then
        Project.DM_Compile;
    For I := 0 To Project.DM_LogicalDocumentCount – 1 Do
    Begin
        ProjectDoc := Project.DM_LogicalDocuments(i);
        If ProjectDoc <> Nil Then
        Begin
            If ProjectDoc.DM_DocumentKind = 'OUTPUTJOB' Then
            Begin
                FileName := ProjectDoc.DM_FullPath;
                ServerDoc  := Client.OpenDocument('OUTPUTJOB',FileName);
                If ServerDoc <> Nil Then
                Begin
                    Client.ShowDocument(ServerDoc);
                    //Process    := 'WorkspaceManager:Print';        
                    //Parameters := 'Action=PrintDocument|ObjectKind=OutputBatch';
                    Process    := 'WorkspaceManager:Print';
                    Parameters := 'Action=PublishToPDF|DisableDialog=True|ObjectKind=OutputBatch';
                    //Process    := 'WorkspaceManager:Print';
                    //Parameters := 'Action=PublishMultimedia|DisableDialog=True|ObjectKind=OutputBatch';
                    //Process    := 'WorkspaceManager:GenerateReport';
                    //Parameters := 'Action=Run|ObjectKind=OutputBatch';
                    RunCommand(Process, Parameters);
                End;
                Exit;
            End;
        End;
    End;
End;

PCB

What is the standard method of modifying PCB primitives?

What should I use instead of PCBServer.SendMessageToRobots?

Code:

procedure UpdateTrackFromObject(aObj: TOutlineObject; aTrack: IPCB_Track);
begin
  PCBServer.PreProcess;
  //PCBServer.SendMessageToRobots(aTrack.I_ObjectAddress, c_BroadCast, PCBM_BeginModify, c_NoEventData);
  try
        aT.X1 := round(aObj.X1);
        aT.Y1 := round(aObj.Y1);
        aT.X2 := round(aObj.X2);
        aT.Y2 := round(aObj.Y2);
  finally
        //PCBServer.SendMessageToRobots(aTrack.I_ObjectAddress, c_BroadCast, PCBM_EndModify, c_NoEventData);
        PCBServer.PostProcess;
  end;
end;

To do this, you should use the following code:

Procedure UpdateTrackFromObject(aObj: TOutlineObject; aTrack: IPCB_Track);
Var
    Board           : IPCB_Board;
    _PCBServer  : IPCB_ServerInterface;
begin
    _PCBServer := PCBServer;
    If _PCBServer = Nil Then
        Exit;
    Board := _PCBServer.GetCurrentPCBBoard;    
    If Board = Nil Then
        Exit;
    _PCBServer.PreProcess;
    Board.DispatchMessage(aTrack, c_Broadcast, PCBM_BeginModify, c_NoEventData);
    try
        aT.X1 := round(aObj.X1);
        aT.Y1 := round(aObj.Y1);
        aT.X2 := round(aObj.X2);
        aT.Y2 := round(aObj.Y2);
    finally
        Board.DispatchMessage(aTrack, c_Broadcast, PCBM_EndModify, c_NoEventData);
        _PCBServer.PostProcess;
    end;
end;

How do I get the active PCB board?

To get the handle of the PCB Board, you need to invoke the PCBServer function and then invoke the GetCurrentPCBBoard method from the PCBServer object;

Var
    Server   : IPCB_ServerInterface;
    PcbBoard : IPCB_Board;
Begin
    Server     := PCBServer;
    PcbBoard   := Server.GetCurrentPCBBoard;
...
End;

How do I iterate PCB objects?

To iterate PCB objects on a PCB document, you need to fetch the PCB document first, and then set up an iterator with initial conditions (such as layers, object types the iteration method) and then run the iteration process until there are no more objects to be found.

How do I iterate specific PCB objects?

To iterate for specific PCB objects, you need to set the Object Set filter of the object iterator with a PCB type.

Code snippet:

Var
    ObjectHandle   : IPCB_Primitive;
    IteratorHandle : IPCB_BoardIterator;
    Server         : IPCB_ServerInterface;
Begin
    Server     := PCBServer;
    PcbBoard   := Server.GetCurrentPCBBoard;
    IteratorHandle := PcbBoard.BoardIterator_Create;
    IteratorHandle.AddFilter_ObjectSet([eNetObject]);
    IteratorHandle.AddFilter_LayerSet(AllLayers);
    IteratorHandle.AddFilter_Method(eProcessAll);
    ObjectHandle := IteratorHandle.FirstPCBObject;
    While ObjectHandle <> Nil Do
    Begin
        ObjectHandle.Index := 0;
        ObjectHandle := IteratorHandle.NextPCBObject;
    End;
    PcbBoard.BoardIterator_Destroy(IteratorHandle);
End;

Another example that looks for pad objects.

Code snippet:

Iterator        := Board.BoardIterator_Create;
Iterator.AddFilter_ObjectSet([ePadObject]);
Iterator.AddFilter_LayerSet_2(cAllLayers);
Iterator.AddFilter_Method(eProcessAll);
// search and count pads
Pad := Iterator.FirstPCBObject;
While (Pad <> Nil) Do
Begin
    PadNumber := PadNumber + 1;
    Pad := Iterator.NextPCBObject;
End;
Board.BoardIterator_Destroy(Iterator);

How do I get selected PCB objects?

You can invoke the Selected property of a PCB design object and get or set the selected boolean value. All PCB objects’ object interfaces are inherited from the IPCB_Primitive interface.

How do I update a PCB object?

When you modify the attributes of a PCB object, you need to invoke the PCB board’s DispatchMessage methods to refresh the PCB object. This is a two step process with PCBM_BeginModify parameter for the DispatchMessage method before the object is being changed and then another DispatchMessage call with the PCBM_EndModify parameter.

Code snippet

Board.DispatchMessage(Component, c_Broadcast, PCBM_BeginModify, c_NoEventData);
    If OriginalHeight <> C Then
    Begin
        Component.Height := C;
        CommandLauncher.LaunchCommand('PCB:Zoom', 'Action=Redraw', 255, Client.CurrentView);
    End;
Board.DispatchMessage(Component, c_Broadcast, PCBM_EndModify, c_NoEventData);

How do I add a new PCB object to the PCB document?

You use the PCBObjectFactory method from the PCBServer object to create a new PCB object and add it to the PCB document. To create a track object, you need to specify whether it is used as a dimension or not. The declaration for this PCBObjectFactory method is as follows;

Function PCBObjectFactory(Const AObjectId : EDPTypes_PCB.TObjectId;
Const ADimensionKind : TDimensionKind;
Const ACreationMode : TObjectCreationMode) : IPCB_Primitive;

The parameters, AObjectID represents the actual design object, ADimensionKind (basically for tracks and arcs) and ACreationMode which is eCreate_Default by default.

An example of creating an arc object;

Code snippet:

_PCBServer := PCBServer;
If _PCBServer = Nil Then
   Exit;
PCB_Board := _PCBServer.GetCurrentPCBBoard;
If PCB_Board  = Nil Then
   Exit;
_PCBServer.PreProcess;
// Current segment is an arc; create an Arc object.
IPrimitive := _PCBServer.PCBObjectFactory(eArcObject,eNoDimension,eCreate_Default);
If IPrimitive = Nil Then
   Exit;
Arc := IPCB_Arc(IPrimitive);
Arc.XCenter    := SegmentI.cx;
Arc.YCenter    := SegmentI.cy;
Arc.Layer      := ALayer;
Arc.LineWidth  := AWidth;
Arc.Radius     := SegmentI.Radius;
Arc.StartAngle := SegmentI.Angle1;
Arc.EndAngle   := SegmentI.Angle2;
PCB_Board.AddPCBObject(Arc);
_PCBServer.PostProcess;

Schematic

How do I add a new Parameter to a Schematic document?

Is it possible to make this Parameter non-visible to the end user (so having some kind of an internal property), or at least make it read-only (and writable only through SDK or several 'clicks' so that a user does not change or delete it by mistake)?

You can manage parameters for Schematic document but you can't set a parameter as hidden or read-only. Here is an example of how to iterate them and add a new parameter:

Procedure Command_SCHDocParameters(View : IServerDocumentView; Parameters : WideString);
Var
    _SCHServer   : ISch_ServerInterface;
    RobotManager : ISch_RobotManager;
    WorkSpace    : IWorkspace;
    Project      : IProject;
    FileName     : String;
    ParamName    : String;
    ParamValue   : String;
    ProjectDoc   : IDocument;
    Sch_Doc      : ISch_Document;
    Sch_Sheet    : ISch_Sheet;
    Iterator     : ISch_Iterator;
    SchParameter : ISch_Parameter;
    SchParameter1: ISch_Parameter;
    Container    : ISch_BasicContainer;
    Container1   : ISch_BasicContainer;
    i            : Integer;
Begin
    WorkSpace := GetWorkspace;
    If WorkSpace = Nil then Exit;
    _SCHServer := SCHServer;
    If _SCHServer = Nil Then Exit;
    RobotManager := _SCHServer.RobotManager;
    If RobotManager = Nil Then Exit;
    ProjectDoc := WorkSpace.DM_FocusedDocument;
    If ProjectDoc <> Nil Then
    Begin
        If ProjectDoc.DM_DocumentKind = 'SCH' Then
        Begin
            FileName := ProjectDoc.DM_FullPath;
            Sch_Doc  := _SCHServer.GetSchDocumentByPath(FileName);
            If Sch_Doc <> Nil Then
            Begin
                Sch_Sheet := ISch_Sheet(Sch_Doc);              
                // Iterating for existing parameter objects.
                Iterator  := Sch_Sheet.SchIterator_Create;
                Iterator.SetState_IterationDepth(eIterateFirstLevel);
                Iterator.AddFilter_ObjectSet([eParameter]);
                Container := Iterator.FirstSchObject;
                While Container <> Nil Do
                Begin
                    SchParameter := ISch_Parameter(Container);
                    ParamName    := SchParameter.Name;
                    ParamValue   := SchParameter.GetState_Text;
                    Container   := Iterator.NextSchObject;
                End;
                Sch_Sheet.SchIterator_Destroy(Iterator);
                // Add a new parameter object and put it on the sheet
                RobotManager.SendMessage(c_FromSystem, c_BroadCast, SCHM_SystemInvalid, c_NoEventData);
                Container1 := _SCHServer.SchObjectFactory(eParameter, eCreate_Default);
                SchParameter1 := ISch_Parameter(Container1);
                SchParameter1.Name := 'TestParam';
                SchParameter1.SetState_Text('TestValue');
                Sch_Sheet.AddSchObject(SchParameter1);
                RobotManager.SendMessage(c_FromSystem, c_BroadCast, SCHM_SystemValid, c_NoEventData);
            End;
        End;
    End;
End;

How do I get an active schematic sheet?

Schematic sheets are part of a project, so to have access to a sheet, you need to fetch the workspace and the schematic server handles. The workspace manager object gives you the ability to find the focused document and then check the document type. Once it is a schematic document type, you can then proceed to add, delete or update schematic objects.

WorkSpace := GetWorkspace;
    If WorkSpace = Nil then
        Exit;
    _SCHServer := SCHServer;
    If _SCHServer = Nil Then
        Exit;
    ProjectDoc := WorkSpace.DM_FocusedDocument;
    If ProjectDoc <> Nil Then
    Begin
        If ProjectDoc.DM_DocumentKind = 'SCH' Then
        Begin
            FileName := ProjectDoc.DM_FullPath;
            Sch_Doc  := _SCHServer.GetSchDocumentByPath(FileName);
            If Sch_Doc <> Nil Then
            Begin
                Sch_Sheet := ISch_Sheet(Sch_Doc); //this is the focused sheet
            End;
        End;
    End;

How do I iterate schematic objects?

To iterate Schematic objects on a Schematic document, you need to fetch the Schematic document first, and then set up an iterator with initial conditions (such as object types and the iteration method) and then run the iteration process until there are no more objects to be found. Note with iterators, it is possible to look for parent objects only or parents and their child objects on a schematic document.

How do I iterate specific schematic objects?

You set up an interator object invoked from the schematic sheet object, set the iteration depth, specify the object types before starting the iteration.

Code snippet

// Iterating for existing parameter objects.
Iterator  := Sch_Sheet.SchIterator_Create;
Iterator.SetState_IterationDepth(eIterateFirstLevel);
Iterator.AddFilter_ObjectSet([eParameter]);
Container := Iterator.FirstSchObject;
While Container <> Nil Do
Begin
    SchParameter := ISch_Parameter(Container);
    ParamName    := SchParameter.Name;
    ParamValue   := SchParameter.GetState_Text;
    Container    := Iterator.NextSchObject;
End;
Sch_Sheet.SchIterator_Destroy(Iterator);

How do I get selected schematic object?

You can invoke the Selection property of a Schematic design object and Get or Set the selected boolean value. Schematic objects’ object interfaces are inherited from the ISch_GraphicalObject interface.

How do I iterate/update/add parameters to schematic object/document?

Code:

Procedure Command_SCHDocParameters(View : IServerDocumentView; Parameters : WideString);
Var
    _SCHServer   : ISch_ServerInterface;
    RobotManager : ISch_RobotManager;
    WorkSpace    : IWorkspace;
    Project      : IProject;
    FileName     : String;
    ParamName    : String;
    ParamValue   : String;
    ProjectDoc   : IDocument;
    Sch_Doc      : ISch_Document;
    Sch_Sheet    : ISch_Sheet;
    Iterator     : ISch_Iterator;
    SchParameter : ISch_Parameter;
    SchParameter1: ISch_Parameter;
    Container    : ISch_BasicContainer;
    Container1   : ISch_BasicContainer;
    i            : Integer;
Begin
    WorkSpace := GetWorkspace;
    If WorkSpace = Nil then
        Exit;
    _SCHServer := SCHServer;
    If _SCHServer = Nil Then
        Exit;
    RobotManager := _SCHServer.RobotManager;
    If RobotManager = Nil Then
        Exit;
    ProjectDoc := WorkSpace.DM_FocusedDocument;
    If ProjectDoc <> Nil Then
    Begin
        If ProjectDoc.DM_DocumentKind = 'SCH' Then
        Begin
            FileName := ProjectDoc.DM_FullPath;
            Sch_Doc  := _SCHServer.GetSchDocumentByPath(FileName);
            If Sch_Doc <> Nil Then
            Begin
                Sch_Sheet := ISch_Sheet(Sch_Doc);
                
                       // Add a new parameter object and put it on the sheet
                RobotManager.SendMessage(c_FromSystem, c_BroadCast, SCHM_SystemInvalid, c_NoEventData);
                Container1 := _SCHServer.SchObjectFactory(eParameter, eCreate_Default);
                SchParameter1 := ISch_Parameter(Container1);
                SchParameter1.Name := 'TestParam';
                SchParameter1.SetState_Text('TestValue');
                Sch_Sheet.AddSchObject(SchParameter1);
                RobotManager.SendMessage(c_FromSystem, c_BroadCast, SCHM_SystemValid, c_NoEventData);
            End;
        End;
    End;
End;

Graphical User Interface of Altium Designer

How do I create menu items in an existing menu and assign my code to be executed?

You need to assign your extension server's process launchers to the new menu items in a target’s menu (the target can be the PCB or the Schematic Editor for example). You need to do three things:

  1. You need to update the resources file (with the RCS file extension) with the Insertion End blocks.
  2. Insert the Updates clause with the name of the target editor (for example the PCB editor has a AdvPCB name) in the project's installation file (with the INS file extension).
  3. Insert the name of your extension server in the ResourceDependencies block of the target editor installation file (the PCB or the Schematic editor’s installation file).

To do this, you need to know the Target ID and Resource reference ID values that indicate where the new menu items should appear in the editor’s menu. These TargetID and RefID0 identifiers can be referenced from the editor’s RCS file in the Altium Designer’s system folder, for example the PCB editor’s AdvPCB.rcs file.

The Process Launcher Tree section in the resources file (with a RCS file extension) defines where the menu items containing the process launchers are going to be attached to in a specific menu.

How do I add my menu item to PCB menu?

  1. You need to update the project resources file (with the RCS file extension) with the Insertion End blocks.
  2. Insert the Updates clause with the ‘AdvPCB’ name within the Server End block in the installation file (with the INS file extension).
  3. Insert the name of your extension project in the ResourceDependencies block in the AdvPCB.ins resources file.

A snippet of a plugin’s installation file:

Server
    EditorName        = 'AddOn'                                                                   
    EditorExePath     = 'AddOn.DLL'                                                               
    EditorDescription = 'Demonstratory AddOn module'                                            
    Version           = 'Version 6.3.0.6689'                                                      
    Date              = '29-Dec-2012'                                                             
    HelpAboutInfo     = 'This software is protected by copyright law and international treaties.'
    Copyright         = 'Copyright © Altium Limited 2012'
    Updates           = 'ADVPCB'                                                                  
End

A snippet of the AdvPCB installation file:

Server
    EditorName        = 'PCB'                                                                     
    EditorExePath     = 'ADVPCB.DLL'                                                              
    EditorDescription = 'Altium Designer PCB Editor'                                        
    Version           = 'Version 10.0.0.28321'                                                      
    Date              = '03-May-2013'                                                             
    HelpAboutInfo     = 'This software is protected by copyright law and international treaties.'
    Copyright         = 'Copyright c Altium Limited 2013'                                         
    SupportsDDB       = True                                                                      

    ResourceDependencies
        'AutoPlacer'
        'CompMake'
        'HSEdit'
        'LayerStackupAnalyzer'
        'Macro'
        'MakeLib'
        'PCB3D'
        'PCBMaker'
        'PCBMiter'
        'Placer'
        'SignalIntegrity'
        'HelpAdvisor'
        'OrcadLayoutImporter'
        'SavePCADPCB'
        'AutoPlacer'
        'PinSwapper'
           'YourPlugInName'
    End
End

How do I create a button and assign this to my extension’s command (process launcher)?

You would need images for such buttons and these bitmaps in 18x18 pixels in size. Copy the button files (with a BMP file extension) into the Altium Designer’s installation ..\System\Buttons folder.

These files are used for the images beside the menu items in a menu of the editor as well as the buttons of a toolbar.

How do I create my own panel?

To add and manage global panel views in your server, you need to build a panel manager object and define its corresponding object interface. This object will manage the global panel. This panel manager object is also exposed as an interface so it can be used in the TServerModule object which represents the Extension.

You will need the Delphi form that represents this panel, and the panel is encapsulated as a private field in the panel manager object as well as in the TServerModule object. To build a global panel view, the global panel view needs to be inherited from the TServerPanelView class, and the global panel form needs to be inherited from the TServerPanelForm class.

The three fields need to be added in the TServerModule class;

  • The panel form (TServerPanelForm)
  • The panel view (TServerPanelView)
  • The panel manager (a standalone class and its interface representation with exposed methods).

Two methods that are added in the TServermodule class;

  • HandleNotification handler
  • CreateServerViews method

A property to add in the TServerModule class;

  • Panel Manager property that represents the panel manager object

TServerPanelForm Object

In the TServerPanelForm constructor, the notification handler is registered with the client module and the self parameter is passed in. The destructor unregisters the notification handler. The HandleNotification method handles whether the panel is changing or not.

TServerPanelView Object

Normally a TServerPanelView object is a direct inheritance from this class and there is no need to add or override methods. These methods are done by the Client system of Altium Designer.

The Panel manager Object

There needs to be an interface representation of the manager within the Panel manager unit, so that the methods needed to manage the global panel are exposed to the system. The interface representation is defined in the manager class, and there is the panel form field as well as the interface methods. When the panel manager is created, the panel form is associated with this manager object so that the panel's form controls can be updated.

TServerModule Object

In the TServerModule constructor, where the server commands are registered, is where to create global panel views and panel managers. The register notification handler needs to be set up here as well. The CreateServerViews method will have the global panel form and the view created with this global panel form. The view is then added to the server module (TServerModule.AddView() method) as well as in the client (Client.AddServerView method). In the ServerModule destructor, the panel manager is set to nil and the notification handler un-registered.

Installation file

The installation file needs to be updated with a new PanelInfo block to reflect the global panel. For example;

PanelInfo
Name = 'GraphicMessages'
Category = 'Graphic'
Bitmap = ''
Hotkey = 'M'
ButtonVisible = True
CanDockVertical = True
CanDockHorizontal = True
End

You can check out the Graphic Viewer example from the SDK folder.

How do I add my panel to PCB panels?

You need to do two things:

  1. Add a global panel in your extension project
  2. Add a PanelInfo End block in the PCB Editor installation file (advpcb.ins).

Example, in the PCB editor’s installation file (advpcb.ins);

PanelInfo
    Name              = 'BoardInSight'
    Category          = '&PCB'                
    Bitmap            = ''                    
    Hotkey            = ''                   
    ButtonVisible     = True                  
    CanDockVertical   = True
    CanDockHorizontal = True
End

How do I create my own editor for files of my type?

You need to do two things to  create your own editor to edit its own document types.

1. Server Module and its Documents in the Main.pas file

The main.pas unit is where the server document classes and the server module class are defined and implemented. The server processes are also defined and implemented in this unit, and a corresponding interfaces unit is defined and linked for these server processes. There is the ServerFactory function which is invoked (only once) by the Client module in Altium Designer when its associated graphic documents are being loaded. That is, the Graphic Viewer server is loaded in memory once.

This main.pas unit deals with two classes – the TServerModule and the TServerDocument classes.

The TServerModule class is inherited and expanded into the TGraphicViewerModule class. The TServerDocument is inherited and expanded into the TGraphicDocument class.

The TServerDocument class implements the processes, controls the panels and views plus the file save and load methods. The processes are declared in the main.pas unit and the interfaces implemented in the commands.pas unit.

 See the GraphicViewer Main.pas file in \Examples\GraphicViewer\ folder of the SDK installation.

2. You need to specify the EditorWindowKind blocks in your editor’s installation file.

Each document kind is represented by this EditorWindowKind block. You will also need to specify the LoadFilters and SaveFilters sub-blocks within each EditorWindowKind block.

You can check out the Graphic Viewer example from the SDK folder.

 

Content