Object kinds¶
Working catalog of CODESYS object kinds for the per-object sync (C# agent,
IObjectManager): what each kind holds, how it goes to disk, and whether it can
be read, replaced and created object by object. One row per kind; details per
kind below the table. Sources: live runtime-reflection probes and per-object
exports of a 1.5k-object customer project (2026-10-10); type and member names
only, no vendor code.
Disk form (target): st = text file with cts pragmas for the fields that are
not part of the text; csv = table; xml = CompactXml archive only (no
text form). Status columns: ok proven live, ? not checked yet, no fails.
| Kind | Type GUID | Seen | Text | Disk form | Export | Replace | Create |
|---|---|---|---|---|---|---|---|
| DeviceObject | 225bfe47-7336-4dbc-9419-4105a7c831fa |
332 | - | xml | ok | ok (no-op) | ? |
| DUTObject | 2db5746d-d284-4425-9f7f-2663a34b0ebc |
310 | yes | st | ok | ok (text) | ok |
| POUObject | 6f9dac99-8de1-4efc-8465-68ac443b7d08 |
203 | yes | st | ok | ok (text, xml) | ok |
| FolderObject | 738bea1e-99bb-4f04-90bb-a7a567e74e3a |
155 | - | xml | ok | ? | ok (tree) |
| EmbeddedFileObject | 9001d745-b9c5-4d77-90b7-b29c3f77a23b |
149 | - | xml | ok | ? | ? |
| POUMethodObject | f8a58466-d7f6-439f-bbb8-d4600e41d099 |
60 | yes | st | ok | ok (text) | ok |
| TextListObject | 2bef0454-1bd3-412a-ac2c-af0f31dbc40f |
57 | table | csv | ok | ok (fields) | ok |
| VisualObject | f18bec89-9fef-401d-9953-2f11739a6808 |
55 | embedded | xml | ok | ok (reorders; agent objects.replace) | ? |
| AlarmGroupObject | 21f4ed1d-ec95-4666-820e-4abf64d93d6b |
46 | - | xml | ok | ? | ok (2 nodes) |
| GVLObject | ffbfa93a-b94d-45fc-a329-229860183b1d |
45 | yes | st | ok | ok (text) | ok |
| PropertyAccessorObject | 792f2eb6-721e-4e64-ba20-bc98351056db |
34 | yes | st | ok | ok (text) | ok (with property) |
| PropertyObject | 5a3b8626-d3e9-4f37-98b5-66420063d91e |
17 | yes | st | ok | ok (text) | ok |
| SlotDeviceObject | 085766fd-043e-4545-8e8d-d651d56d5d3b |
12 | - | xml | ok | ok | ? |
| ExternalFileObject | a56744ff-693f-4597-95f9-0e1c529fffc2 |
8 | - | xml | ok | ? | ? |
| TaskObject | 98a2708a-9b18-4f31-82ed-a1465b24fa2d |
6 | - | xml | ok | ok (fields) | ok |
| TaskPOUCallObject (hidden) | 413e2a7d-adb1-4d2c-be29-6ae6e4fab820 |
6 | - | xml | ok | ? | ? |
| AlarmClassObject | b8b46f61-c7c1-4259-87e4-26fe674798f9 |
5 | - | xml | ok | ? | ? |
| HiddenTransientImagePoolObject (hidden) | 8e687a04-7ca7-42d3-be06-fcbda676c5ef |
2 | - | xml | ok | ? | ? |
| LibManObject | adb5cb65-8e1d-4a00-b70a-375ea27582f3 |
2 | - | xml | ok | ? | ? |
| SymbolConfigObject | 21d4fe94-4123-4e23-9091-ead220afbd1f |
1 | - | xml | ok | ? | ? |
| ProjectInfoObject | 085afe48-c5d8-4ea5-ab0d-b35701fa6009 |
1 | - | xml | ok | ? | ? |
| PlcLogicObject | 40b404f9-e5dc-42c6-907f-c89f4a517386 |
1 | - | xml | ok | ? | ? |
| TraceObject | f7aa3620-8073-4c91-b6ec-86ed9eb60303 |
1 | - | xml | ok | ? | ? |
| ApplicationObject | 639b491f-5557-464c-af91-1471bac9f549 |
1 | - | xml | ok | ? | ? |
| WorkspaceObject | 8753fe6f-4a22-4320-8103-e553c4fc8e04 |
1 | - | xml | ok | ? | ? |
| DatabaseFileAlarmStorageObject | 5bd56248-46fc-4108-be33-ed01ad87d070 |
1 | - | xml | ok | ? | ? |
| VisualManagerObject | 4d3fdb8f-ab50-4c35-9d3a-d4bb9bb9a628 |
1 | - | xml | ok | ? | ? |
| WebVisualizationObject | 0fdbf158-1ae0-47d9-9269-cd84be308e9d |
1 | - | xml | ok | ? | ? |
| GlobalTextListObject | 63784cbb-9ba0-45e6-9d69-babf3f040511 |
1 | table | csv | ok | ok | ? |
| ImagePoolObject | bb0b9044-714e-4614-ad3e-33cbdf34d16b |
1 | - | xml | ok | ? | ok |
| TaskConfigObject | ae1de277-a207-4a28-9efb-456c06bd52f3 |
1 | - | xml | ok | ? | ? |
| ExplicitConnector | e9159722-55bc-49e5-8034-fbd278ef718f |
1 | - | xml | ok | ? | ? |
| AlarmConfigurationObject | c0a56ce5-14a3-4757-ac56-3eab44c974b3 |
1 | - | xml | ok | ? | ? |
| ActionObject | 8ac092e5-3128-4e26-9e7e-11016c6684f2 |
0 | yes | st | ok | ok (text) | ok |
| TransitionObject | a10c6218-cb94-436f-91c6-e1652575253d |
0 | yes | st | ? | ? | ok |
| InterfaceObject | 6654496c-404d-479a-aad2-8551054e5f1e |
0 | yes | st | ok | ok (text) | ok |
| InterfaceMethodObject | f89f7675-27f1-46b3-8abb-b7da8e774ffd |
0 | yes | st | ok | ? | ok |
| AbstractPOUMethodObject | 62ebfd1c-d342-43e5-8efb-f22b6d8e4a04 |
0 | yes | st | ? | ? | ? |
| POUObjectCheckFunction | c3fc9989-e24b-4002-a2c7-827a0a2595f4 |
0 | yes | st | ? | ? | ? |
| NVLObject | 722bc402-e00b-490a-8138-0a7d01b3426e |
0 | yes | st | ? | ? | no (wizard) |
| VarPersistentObject | 261bd6e6-249c-4232-bb6f-84c2fbeef430 |
0 | yes | st | ? | ? | ok |
| TasklocalGVLObject | c2cda7a9-0ba4-4146-b563-22a42fa0eb72 |
0 | yes | st | ? | ? | ok |
| RecipeManObject | 09ecc42e-586d-4a08-932f-5bdcac20bb55 |
0 | - | xml | ? | ? | ? |
| RecipeDefinitionObject | 6b3dfb6a-1865-4356-a39b-1fe0ef89651c |
0 | table | csv? | ? | ? | ? |
| UnitConversionObject | 9031c721-d39f-4557-8a8f-ab12b4a71ebc |
0 | - | xml | ? | ? | ? |
Rows with Seen 0 come from the runtime metadata of CODESYS 3.5.22.30 (classes
with a TypeGuid that implement IObject), not from a project yet. Export ok:
CompactXml per-object export equals the object's entry in export_native
(1509/1509 on the bench). The two hidden kinds are not in export_native and
are skipped. Text embedded: the visualization carries generated text inside
its element tree, not a user document.
Implementations (embedded in POU, method, action, transition)¶
The body of a text-bearing kind is an embedded implementation object; its kind decides whether the body can be text.
| Implementation | Type GUID | Body |
|---|---|---|
| STImplementationObject | 3b83b776-fb25-43b8-99f2-3c507c9143fc |
text (st) |
| VarDeclObject (declaration) | a9ed5b7e-75c5-4651-af16-d2c27e98cb94 |
text (st) |
| SFCImplementationObject | 74f81948-1328-492c-b6c1-a9ea72048b28 |
graphical (xml) |
| CFCImplementationObject | 32d3375e-c010-41e2-9e43-b2fbf4f2b374 |
graphical (xml) |
| PageOrientedCFCImplementationObject | 30124a67-851d-45eb-873a-0374fa1cfa68 |
graphical (xml) |
| LadderImplementationObject | f0fda5b8-8c48-4377-bbd5-c49444e4d26e |
graphical (xml) |
| NWLImplementationObject (FBD/LD/IL networks) | 25e509de-33d4-4447-93f8-c9e4ea381c8b |
graphical (xml) |
A POU with a graphical body keeps its declaration as text; the body stays xml.
Object properties (meta Properties, outside the text)¶
Attached to the meta object, not to the object itself; candidates for cts pragmas on text kinds.
Full scan of the bench (2026-10-10, all 669 text objects: 310 DUT, 203 POU,
60 method, 45 GVL, 34 accessor, 17 property): apart from the text and the
folder, the only non-default values are ExcludeFromBuild=True (41 POUs) and
LinkAlways=True (2 GVLs). IsGet of an accessor follows from its name, the
other object fields (POULevel, SpecialFunc, AddAttributeSubsequent,
ParameterList, NetVarProperties) keep their defaults everywhere. So a text
kind on disk needs only its text, its path and the BuildProperty pragmas.
| Property | Type GUID | Settable members | Seen on |
|---|---|---|---|
| BuildProperty | 24568a24-c491-472c-a21f-ee5d33859fab |
ExcludeFromBuild, ExcludeFromBuildLocal, External, EnableSystemCall, LinkAlways, CompilerDefines, Undefines, MemoryReserveForOnlineChange | 55 of 203 POUs (41 ExcludeFromBuild=True), 3 GVLs (2 LinkAlways=True), 1 DUT |
| SVFoldersProperty | 829a18f2-c514-4f6e-9634-1df173429203 |
(folder membership) | almost every object; structural, comes from the path |
| VisualProperty | 477d844b-9b2a-407e-90a4-d36fd6dde2fc |
VisuSizeMode, UsageType, Size, IsStartVisu, Internal, … | visualizations |
| TextListPropertiesObject | 9db18249-9fcf-4264-a9de-410a659a36b3 |
Internal, DownloadForApplication | text lists |
| ImagePoolPropertiesObject | a67e96c6-3fd3-4d25-a9ff-723c6b2f78cb |
DownloadOnlyUsedImages, Internal, SymbolTextList, DownloadByVisu | image pools |
| ObjectAccessProperty | 66e0aa87-603e-4e95-b7ac-da3c4a099b35 |
(access rights) | ? |
| DeviceProperty | cdadfc2b-8598-4621-ad56-5b1df7db910f |
(device identification) | devices |
657bb752-68e4-4ef6-a654-6d13f38a3c55 |
not in public metadata | ? | ? |
API (proven 2026-10-10)¶
- Export:
IObjectManager2.ExportObject(handle, guid, metaStream, objectStream, writer), writerCompactXmlArchiveWriter{47B44770-18B8-4f47-92CC-AD8DD6B5B1B9}. - Read into an object without placing it:
IObjectManager2.ImportObject(meta, object, reader, out parent, out guid, out obj, out name, out properties), readerCompactXmlArchiveReader{6F129F88-6420-403f-B776-7752427BD61F}. - Replace:
GetObjectToModify(handle, guid)->IMetaObject2.ReplaceObject(obj)->SetObject(meta, true, null). A MetaObject property travels separately:IMetaObject.RemoveProperty(typeGuid), thenAddProperty(property)with the oneImportObjectread from the file (a property's key is theTypeGuidattribute of its class). The Library Manager writes its placeholder resolutions back as properties after its libraries change (persisted on save). The agent'sobjects.replacereads the documents from the disk.xmlentry (itsMetaObject/Objectmembers re-rooted): the reader takes the export's canonical form (Timestamp dropped, entry indentation) unchanged, live on a visualization and a device (~0.1 s each). - Write text:
GetObjectToModify(handle, guid)->Object.Interface.TextDocument.Text = sand/orObject.Implementation.TextDocument.Text = s->SetObject(meta, true, null). Every text kind exposesInterfaceasIVarDeclObjectandImplementationasIImplementationObject(action: body only; accessor: body, declarationVAR END_VAR). 50-170 ms. The text is stored verbatim: LF stays LF (only the archive writer emits CRLF), non-ASCII and pragmas survive, the compiler sees the change. A write bumpsTimeStampandUniqueIdGenerator, so writing the old text back is not a byte-equal undo. Unreferenced POUs are not compiled: a build does not prove their text. - Create:
AddObject(handle, parent, guid, obj, name, -1); the caller chooses the guid. Without an XML template, the way the IDE's "Add Object" does it (proven live):IObjectManager.ObjectFactoryManager.Factories(80 factories; no system instance of the manager) -> factoryCreate(string[] batchArguments)->AddObject-> factoryObjectCreated(handle, guid, batchArguments)(the 3-argument form when present, once: it adds children such as property accessors).AcceptsParentObject(IObject parent)answers the parent constraint. 100-550 ms per object on the bench. - Batch arguments: build the factory's wizard page (
WizardPage, orIObjectFactory3.GetWizardPage(handle, parent)for methods), callControl.CreateControl()so the page loads its language list, thenCreateBatchArgumentsFromWizardPage(page)returns the defaults. The declaration argument becomes the Interface text verbatim; the body starts as empty ST. The language guid is theTypeGuidof the implementation factory (public metadata); the page'sSelectLanguage(name)does not switch it:
| Language | Guid |
|---|---|
| ST | cc393387-a21c-4f68-a3e3-84c36951965d |
| SFC | ba020298-5c00-4558-8da5-551cff5b4aa9 |
| CFC | a4e3bc72-255d-4cf1-93a5-3d12da67b2e1 |
| CFC (page-oriented) | 13c55f2e-a820-4b3a-8a86-f42bd395d87f |
| FBD/LD/IL networks | c2e2244b-c806-41b4-8ad3-7a0e25ce1393 |
| LD | 29148beb-8dd2-4bb8-8b77-ab9fe196c1ba |
| IL | 7ced0289-1a1e-4049-afc8-6b798c73f499 |
| Ladder | 9cb75521-cc3e-44e6-a4f7-e66d155fada2 |
| Factory | Batch arguments (defaults) |
|---|---|
| POUObjectFactory | [Guid.Empty, language, "", declaration, "4"] |
| POUMethodObjectFactory | [Guid.Empty, declaration, language, "False"] |
| PropertyObjectFactory | [Guid.Empty, declaration, language, "False", "True" (Get), "True" (Set)] |
| ActionObjectFactory | [language] |
| DUTObjectFactory | [Guid.Empty, declaration] |
| InterfaceObjectFactory | [Guid.Empty, declaration] |
| GVLObjectFactory, FolderObjectFactory | [] (no wizard arguments) |
| InterfaceMethodObjectFactory | [Guid.Empty, declaration] |
| InterfacePropertyObjectFactory | [Guid.Empty, declaration] (PROPERTY <name> : <type>) |
| VarPersistentObjectFactory | []; text starts as {attribute 'qualified_only'} VAR_GLOBAL PERSISTENT RETAIN END_VAR |
| TransitionObjectFactory | [language] (under an SFC POU) |
| NVLObjectFactory | none: its wizard page needs the project's GVLs and task names and fails standalone |
- Read fields: every kind implements IArchivable; SerializableValueNames and |
|
GetSerializableValue(name) return the persisted field tree (the same names as |
|
| the CompactXml archive). Values are scalars, nested archivables, or | |
ArrayList/Hashtable/LList collections of them. The same holds for the |
|
meta object's Properties. All 33 kinds of the bench in 1.4 s. |
|
- Write fields: GetObjectToModify -> walk the path with GetSerializableValue |
|
(Watchdog.Time.Time, TextList[0].LanguageTexts[0]) -> |
|
SetSerializableValue(name, value) with the old value's type (string, enum, |
|
primitive), or IList[i] = value for a list item -> SetObject(meta, true, null). |
|
| 7-150 ms (2 s on a device). Proven on task fields, text list rows (non-ASCII), | |
TextListPropertiesObject and a device IO mapping; code generation sees task |
|
| changes. Adding and removing | |
list items: clone an item (ICloneable, deep), set its fields, IList.Insert; |
|
remove with IList.RemoveAt; then SetObject. 40-130 ms. Proven on text list |
|
rows and task calls (PouList, the call appears in the generated task code). |
|
An empty list has nothing to clone: build the item with its public () ctor |
|
(_3S.CoDeSys.TaskObject.PouObject, _3S.CoDeSys.TextList.TextListRow). |
|
- Generated code: ILanguageModelProvider.GetLanguageModel() returns the |
|
<language-model> XML with the implicit IEC code the compiler gets (task info, |
|
| IO-config GVLs, text-list and alarm FBs). It is read-only and not a disk form. | |
On VisualManagerObject it raises a debug assertion dialog that blocks the IDE: |
|
| never call it there. | |
- Delete: RemoveObject(handle, guid). |
|
- Meta properties: IMetaObject.Properties and GetProperty(Guid) read them, |
|
AddProperty(IObjectProperty) adds one the object lacks, RemoveProperty(Guid) |
|
drops it (the object must be checked out with GetObjectToModify and committed |
|
with SetObject). A property is created by type: its public class name (e.g. |
|
BuildProperty, 24568a24-c491-472c-a21f-ee5d33859fab) found among the loaded |
|
assemblies as an IObjectProperty, then the public parameterless constructor. |
|
- Change detection: IMetaObject.TimeStamp (persisted) and ObjectModified/Added/Removed events. |
Per kind¶
POUObject¶
- Text:
Interface.TextDocument(declaration),Implementation.TextDocument(body). - Non-text, user-settable (pragma candidates):
Level(POULevel,Standardeverywhere on the bench),KindOfCheckFunction(xmlSpecialFunc,None),AddAttributeSubsequent(False), plus BuildProperty. - Volatile:
LineInfoPersistence(<guid>_Impl_LineIds/_Decl_LineIds),UniqueIdGenerator. - Replace: ok, 30-80 ms, round trip byte-identical. Create: ok from an XML template and through POUObjectFactory (PROGRAM, FUNCTION_BLOCK, FUNCTION with return type; the kind follows from the declaration text).
- Members: method (POUMethodObjectFactory, under FB or PROGRAM), action
(ActionObjectFactory, under PROGRAM), property (PropertyObjectFactory, under
FB; Get/Set accessors are created by
ObjectCreatedfrom the arguments).
DUTObject, GVLObject¶
- Text:
Interface.TextDocumentonly. Non-text: BuildProperty (1 DUT on the bench). Volatile:LineInfoPersistence,UniqueIdGenerator.
FolderObject¶
- Folders sit at the project root (Parent = Guid.Empty, all 155 on the bench).
Where a folder or object appears in the tree is the
SVFoldersPropertydictionary ParentObjects {structured view guid -> parent folder or Application}; the bench has one view,d9b2b2cc-ea99-4c3b-aa42-1e5c49e65b84. - Create in the tree (proven):
GetStructuredView(handle, sv).GetNode(parent) .AddObject(guid, factoryObject, name, -1), then the factory'sObjectCreated. The new guid is found by name amongGetNode(parent).Children. A folder stays a root object with SVFoldersProperty {sv -> Application or outer folder}; a POU added to a folder node gets ParentObjectGuid = Application and SVFoldersProperty {sv -> folder}, the same shape as the bench objects. - Move:
ISVNode.MoveObject(newParentNode, -1), 30-55 ms; only SVFoldersProperty changes. Moving straight under Application removes the property entry.
DeviceObject (IO mapping)¶
- The device stays xml, but its IO mapping is a table: under
ConnectorList.InnerList[c].HostParameterSet.Params[p].DalaElement(and itsSubElements.elements[e],BaseType) sitsIoMapping{Mappings.Mappings[k]{Id, Variable}, IecAddress, AutomaticAddress}.Variableis the mapped variable (Application.PN41.CMD_...); writing it through the field path works. Candidate disk form: one csv per device with channel, variable, address. - Volatile:
PositionId,EditorPositionIdon the parameter elements; an element saved without them gets them when a later session opens the device.PlaceholderResolution(placeholder -> library, rebuilt from the PC's installed libraries) is not compared either, and the export writes it as<Null>: the IDE fills it again as soon as the device is replaced from the file (measured on a device resolving IoDrvEthernet; the build is unchanged).
TaskObject¶
- Fields:
Kindoftask(Cyclic, Freewheeling, …),Priority,Interval{Time, Unit},Watchdog{Enabled, Time {Time, Unit}, Sensitivity},Event,ExternalEvent,PouList[{Name, Comment}],Core2,TaskGroup,WithinSPSTimeSlicing,SynchTask, parameter lists (IntervalParameters, …). - Volatile:
TaskGuid,EventPOUGuid(generated code). - Field writes reach the code generator: Task Configuration's language model
shows the new
nPriority/KindOf/bWatchdog, and an enabled watchdog without a time becomes{error '<task>: The watchdog time is invalid.'}. - Create:
TaskObjectFactoryargs[]under Task Configuration (wizard has no batch overload); starts as Cyclic, priority 1,t#4ms, emptyPouList. A new task with one call shows up asCallTask__<task>in the generated code.
TextListObject, GlobalTextListObject¶
- Fields:
Languages[string],TextList[TextListRow {TextID, TextDefault, LanguageTexts [string, one per language]}]: a table with the columns ID, Default, then one per language. - Property: TextListPropertiesObject {DownloadForVisu, DownloadForApplication, Internal}.
- Volatile:
GuidInit,GuidReInit,GuidExitX,UniqueIdGenerator. - Create:
TextListObjectFactoryargs[]under Application, ~2 s; starts with one empty row and no languages.GlobalTextListObjectFactoryis a different factory (one per project, root only): pick factories by exact class name, a substring match picks the Global one.
ImagePoolObject¶
- Fields:
BitmapPool[ImagePoolItem {BitmapID, FileID, ItemID}];FileIDnames an EmbeddedFileObject (<guid>|<original path>), whoseDataholds the bytes. - Create:
ImagePoolObjectFactoryargs[]under Application.
AlarmGroupObject, AlarmClassObject¶
- Group:
Alarms{key -> Alarm {ID, ObservationType (e.g. DigitalObservation {Expression, Comparison, ExpressionToCompare}), AlarmClass {Name, Guid}, LatchVariable1.., MinPendingTime, Deactivation}},TextListReference,Deactivation,AlarmStorage. - Class:
Priority,AcknowledgeMethod,Archiving,NotificationActions,DisplayOptions,ReAlarmTime. - Volatile:
LanguageModelData(generated-code guids),InternalID. - Create:
AlarmGroupObjectFactoryargs[]under the Alarm Configuration object, ~3.6 s.ObjectCreatedadds a second node with the same name, whichTextListReferencepoints to: most likely the group's own text list (type not checked).
TraceObject¶
- Fields:
TraceSettings,Record{TaskName, BufferEntries, Trigger*,VariableList[TraceVariable {VariableName, GraphColor, …}]}.
Hidden kinds¶
- TaskPOUCallObject and
__VisualizationStyleget new guids in every IDE session, and the style carries a per-session temp path: never sync them. The application's own copy of the style is exported; its default bitmaps sit under the session's temp directory and take a newItemIDin every session, so the normal form ignores both.
VisualObject¶
- Replace: ok, but key/value lists come back in another order
(
ieccodeconversion_array/DefaultArraySize,conditionalshow/DisplayFrameReferencesConfiguration): the normal form sorts these lists by key, keeping each pair together. - Once, between IDE sessions, six table-control visualizations differed
without an edit:
LibraryIdvisuelemswincontrols4.5.0.0 vs 4.10.0.0 and extra''NORMAL__COMMENTentries. A later session (3.5.22.30) compared all of a large project's visualizations unchanged, so the normal form keeps both.