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 withRegisterCommand
procedure - Comments: Replace
AddCommand
method withRegisterCommand
for theCommandLauncher
as an aggregate class of theTServerModule
class. The AddCommand method doesn't exist in Altium Designer. Use theRegisterCommand
method instead to store a declared command (process) in the server table in Altium Designer. - Replace
Stdcall
withSafeCall;
- 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
withWideString
methods. - Comments: The
NewDocumentInstance
method of aTServerModule
has its parameter signature changed slightly – replace PChars withWideStrings
.
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:
- 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'sUses
clause. - Make sure the unit associated with the new form is in focus. Add the appropriate Altium Designer APIs, for example
EDPClasses
to theUses
directive for this new unit. - 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:
- Find
OutputJob
file in the project (iterating through the logical documents). - Open this file and make it active.
- 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:
- You need to update the resources file (with the
RCS
file extension) with the Insertion End blocks. - 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 theINS
file extension). - 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?
- You need to update the project resources file (with the
RCS
file extension) with the Insertion End blocks. - Insert the Updates clause with the ‘
AdvPCB
’ name within the Server End block in the installation file (with theINS
file extension). - 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
handlerCreateServerViews
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:
- Add a global panel in your extension project
- 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.