eae-fork
npx skills add https://github.com/sapiencezk/eae-skills --skill eae-fork
Agent 安装分布
Skill 文档
EAE Block Fork – Hybrid Manual/Automated Workflow
Fork function blocks from Schneider Electric standard libraries into your custom library using a hybrid approach that combines the best of manual and automated workflows.
v7.2 ENHANCED – Production-Ready Reliability:
- Manual fork in EAE GUI â Perfect HMI files (generated by EAE’s designer)
- Automated finalization â Single-command execution updates ALL references
- â Root namespace updates
- â Cross-block references (FB/SubCAT in .fbt files)
- â HMI cross-references (fully qualified types in Designer.cs)
- â GUID generation + Registration
- â Transactional rollback – Automatic recovery from failures (v7.1)
- â UTF-8 encoding – Works on international Windows systems (v7.1)
- ð Pre-fork validation – Catches errors before manual fork in GUI (v7.2)
- ð Better error messages – Contextual help with recovery suggestions (v7.2)
- ð Resume capability – Gracefully handles interrupted forks (v7.2)
- ð Dependency auto-detection – Automatically suggests all SubCATs to fork (v7.2)
Why this approach?
- â Perfect HMI files – EAE’s GUI generates flawless Designer.cs files
- â Complete automation – One command handles all namespace updates
- â Cross-reference handling – Automatically updates references between forked blocks
- â Fast – ~15 seconds per hierarchy (vs 3+ minutes manual editing)
- â User control – Full visibility in GUI during fork
- â Failure-safe – Auto-rollback protects your project from corruption
- ð Resumable – Interrupted forks can be resumed from last successful block
Separation of Concerns:
- eae-fork (this skill): Finalize manually forked blocks (namespaces, GUIDs, registration)
- eae-cat: Register CAT blocks in dfbproj AND csproj (when called with
--register-only) - eae-composite-fb: Register composite blocks in dfbproj (when called with
--register-only) - eae-basic-fb: Register basic blocks in dfbproj (when called with
--register-only) - eae-adapter: Register adapters in dfbproj (when called with
--register-only) - eae-datatype: Register data types in dfbproj (when called with
--register-only)
Quick Start
Interactive Guided Workflow – Just tell the skill what you want:
You: Fork AnalogInput into SE.ScadapackWWW
Claude:
ð Analyzing AnalogInput...
This block requires a 3-level hierarchy:
1. AnalogInputBase (core logic)
2. AnalogInputBaseExt (extended features)
3. AnalogInput (full implementation)
ð Please fork these blocks in EAE GUI:
Steps:
1. Open EAE GUI
2. Navigate to SE.App2CommonProcess library
3. For each block, right-click â "Copy Block"
â AnalogInputBase â SE.ScadapackWWW
â AnalogInputBaseExt â SE.ScadapackWWW
â AnalogInput â SE.ScadapackWWW
4. Reply 'done' when complete
You: done
Claude:
ð§ Finalizing fork...
â Validated 3 blocks manually forked
â Updated namespaces in .fbt files (SE.ScadapackWWW)
â Updated namespaces in .cs files (15 files)
â Generated new GUIDs
â Registered in dfbproj/csproj
â
Fork complete! Blocks ready to use in SE.ScadapackWWW.
What the skill does:
- ð Analyzes block hierarchy and dependencies
- ð Guides you through manual fork in EAE GUI
- â¸ï¸ Waits for your confirmation
- ð§ Executes finalization script – Single command updates everything:
- Root namespaces in .fbt files
- Cross-block references (FB/SubCAT elements)
- HMI namespaces in .cs files
- HMI cross-references (fully qualified types)
- New GUIDs for all blocks
- Project registration (dfbproj/csproj)
- â Reports complete summary with counts
Alternative: Manual Finalization
If you’ve already forked in EAE GUI:
/eae-fork --finalize AnalogInput
Triggers
| Trigger | Description |
|---|---|
/eae-fork |
Primary invocation |
fork block from library |
Natural language |
copy block to custom library |
Alternative phrasing |
migrate block namespace |
Namespace-focused |
customize EAE block |
Customization intent |
CRITICAL: Fork Depth Selection
Before forking, ALWAYS ask the user about fork depth:
How deep should the fork go?
1. **Single block only** (Recommended for minor customization)
- Fork only AnalogInput
- Uses original library's AnalogInputBaseExt
- Smallest footprint, easy to maintain
2. **Fork hierarchy** (Base â BaseExt â Full)
- Fork AnalogInputBase, AnalogInputBaseExt, AND AnalogInput
- Full control over the entire block chain
- Best for significant modifications
3. **Fork with all SubCATs**
- Fork hierarchy PLUS all SubCAT blocks (LimitAlarm, DeviationAlarm, etc.)
- Maximum customization capability
- Largest footprint, most maintenance
Which option do you prefer? (1/2/3)
How It Works – Streamlined Workflow (v7.0)
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â PHASE 1: ANALYZE & GUIDE (Automatic) â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ¤
â User: "Fork AnalogInput into SE.ScadapackWWW" â
â â
â Skill analyzes: â
â 1. Identify block hierarchy (Base â BaseExt â Full) â
â 2. Detect dependencies (SubCATs, referenced blocks) â
â 3. Determine target library details â
â â
â Skill generates guided instructions: â
â ⢠List of blocks to fork (with checkboxes) â
â ⢠Step-by-step EAE GUI instructions â
â ⢠Clear confirmation prompt â
â â
â Output: Checklist for user to follow â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â
â¼
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â PHASE 2: MANUAL FORK IN EAE GUI (User) â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ¤
â User performs fork using EAE's built-in functionality: â
â â
â For each block in checklist: â
â 1. Open EAE GUI â
â 2. Navigate to source library (e.g., SE.App2CommonProcess) â
â 3. Right-click block â "Copy Block" â
â 4. Select target library (e.g., SE.ScadapackWWW) â
â 5. Wait for EAE to generate files â
â â
â EAE generates perfect files: â
â ⢠IEC61499/{Block}/ (all .fbt, .cfg, .xml files) â
â ⢠HMI/{Block}/ (perfect Designer.cs files) â
â â
â â
Perfect HMI files (EAE's designer) â
â â
All visual properties preserved â
â â
No decompilation needed â
â â
â User replies: "done" â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â
â¼
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â PHASE 3: FINALIZE FORK - SINGLE COMMAND (Automatic) â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ¤
â â
â Command Executed: â
â python finalize_manual_fork.py \ â
â AnalogInputBase AnalogInputBaseExt AnalogInput \ â
â LimitAlarm DeviationAlarm ROCAlarm \ â
â SE.ScadapackWWW â
â â
â What the script does automatically: â
â â
â [1/4] VALIDATE MANUAL FORK â
â ⢠Detect source namespace from existing files â
â ⢠Check all blocks forked (IEC61499/ and HMI/) â
â ⢠Detect block types (.cfg â CAT, etc.) â
â ⢠Verify file completeness â
â â
â [2/4] UPDATE NAMESPACES & CROSS-REFERENCES â
â ⢠Root declarations: Namespace="SE.ScadapackWWW" â
â ⢠FB/SubCAT elements: Update refs to forked blocks â
â ⢠HMI namespaces: Update Symbols/Faceplates namespaces â
â ⢠HMI cross-refs: Update fully qualified type references â
â ⢠Generate new GUIDs (12 total: 2 per block) â
â â
â [3/4] REGISTER IN PROJECT â
â ⢠Detect block type (CAT/Composite/Basic) â
â ⢠Call registration script for each block â
â ⢠dfbproj entries (Compile/None ItemGroups) â
â ⢠csproj entries (CAT HMI files) â
â â
â [4/4] REPORT SUMMARY â
â ⢠Successful: 6/6 blocks â
â ⢠Cross-references updated: 24 â
â ⢠HMI references updated: 18 â
â â
â Output: "â
All blocks finalized successfully!" â
â â
â Time: ~15 seconds (vs 3+ minutes manual editing) â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
Why This Workflow?
| Aspect | Manual Fork + Finalize | Old Automated Approach |
|---|---|---|
| HMI Files | â Perfect (EAE-generated) | â Decompiled (format issues) |
| Complexity | â Low (simple namespace update) | â High (ILSpy, post-processing) |
| Reliability | â 100% (proven EAE workflow) | â ~70% (decompilation artifacts) |
| Speed | â ~30 sec/block | â ï¸ ~2 min/block |
| User Control | â Full visibility in GUI | â ï¸ Black box automation |
| Maintenance | â Easy (140 lines of code) | â Hard (500+ lines) |
Phase 3 Detail: Registration by Block Type
CAT Blocks (most common):
/eae-cat --register-only {BlockName} {Namespace}
â
âââ dfbproj: Add Compile entries for .fbt, _HMI.fbt
âââ dfbproj: Add None entries for .cfg, .offline.xml, .opcua.xml
âââ csproj: Add Compile entries for HMI .cs files
âââ csproj: Add EmbeddedResource entries for .resx, .xml
âââ Folders.xml: Add folder entry
Composite FB:
/eae-composite-fb --register-only {BlockName} {Namespace}
â
âââ dfbproj: Add Compile entry for .fbt (IEC61499Type=Composite)
Basic FB:
/eae-basic-fb --register-only {BlockName} {Namespace}
â
âââ dfbproj: Add Compile entry for .fbt (IEC61499Type=Basic)
Adapter:
/eae-adapter --register-only {BlockName} {Namespace}
â
âââ dfbproj: Add Compile entry for .adp (IEC61499Type=Adapter)
DataType:
/eae-datatype --register-only {BlockName} {Namespace}
â
âââ dfbproj: Add Compile entry for .dt (IEC61499Type=DataType)
eae-fork Responsibilities (Steps 1-5)
Step 1: Copy IEC61499 Files
Copy from source library to target:
| Source | Target |
|---|---|
Libraries/{Lib}/Files/{Block}/ |
{Project}/{Target}/IEC61499/{Block}/ |
IEC61499 Files to copy:
{Block}.fbt - Main block definition (XML)
{Block}.cfg - CAT configuration (links to HMI)
{Block}.doc.xml - Documentation (optional)
{Block}_HMI.fbt - HMI interface block
{Block}_CAT.offline.xml - Offline parameters
{Block}_CAT.opcua.xml - OPC-UA config
{Block}_HMI.offline.xml - HMI offline parameters
{Block}_HMI.opcua.xml - HMI OPC-UA config
Step 2: Decompile & Transform HMI Files (CRITICAL)
HMI files must be DECOMPILED from the source library DLL. Standard Schneider Electric libraries ship only compiled HMI DLLs – no source files exist in the Files/ directory for HMI.
| Source | Target |
|---|---|
Libraries/{Lib}-{Ver}/HMI/{Lib}.HMI.dll (DECOMPILE) |
{Project}/{Target}/HMI/{Block}/ |
Decompilation Process:
# Use the decompile_hmi.py script
python scripts/decompile_hmi.py SE.App2CommonProcess AnalogInputBase SE.ScadapackWWW ./output
# Or with hierarchy (multiple blocks)
python scripts/decompile_hmi.py SE.App2CommonProcess AnalogInput SE.ScadapackWWW ./output \
--forked-blocks AnalogInputBase AnalogInputBaseExt AnalogInput
What the decompilation does:
- Locates the HMI DLL in
C:\ProgramData\Schneider Electric\Libraries\{Lib}-{Ver}\HMI\ - Decompiles using ILSpy CLI (ilspycmd)
- Finds symbol/faceplate classes in
{Lib}.Symbols.{Block}/and{Lib}.Faceplates.{Block}/directories - Splits decompiled classes into EAE format:
.cnv.cs(main) +.cnv.Designer.cs(InitializeComponent) - Updates namespaces according to the rules below
- Creates
.cnv.resxand.cnv.xmlfiles
HMI Files to copy (per symbol/faceplate):
{Block}.def.cs - Faceplate accessor definitions
{Block}.event.cs - Event argument classes
{Block}.Design.resx - Design resources
{Block}_fpDefault.cnv.cs - Faceplate implementation
{Block}_fpDefault.cnv.Designer.cs - Designer-generated code
{Block}_fpDefault.cnv.resx - Faceplate resources
{Block}_fpParameter.cnv.cs - Parameter faceplate
{Block}_fpParameter.cnv.Designer.cs
{Block}_fpParameter.cnv.resx
{Block}_fpTrend.cnv.cs - Trend faceplate
{Block}_fpTrend.cnv.Designer.cs
{Block}_fpTrend.cnv.resx
{Block}_sDefault.cnv.cs - Default symbol
{Block}_sDefault.cnv.Designer.cs
{Block}_sDefault.cnv.resx
{Block}_sDefault.cnv.xml - Symbol XML (ONLY for symbols)
{Block}_sVertical.cnv.cs - Vertical symbol
{Block}_sVertical.cnv.Designer.cs
{Block}_sVertical.cnv.resx
{Block}_sVertical.cnv.xml
{Block}_sDisplayPv.cnv.cs - Display PV symbol
{Block}_sDisplayPv.cnv.Designer.cs
{Block}_sDisplayPv.cnv.resx
{Block}_sDisplayPv.cnv.xml
{Block}_sInstanceName.cnv.cs - Instance name symbol
{Block}_sInstanceName.cnv.Designer.cs
{Block}_sInstanceName.cnv.resx
{Block}_sInstanceName.cnv.xml
Important: Faceplates (fp*) do NOT have .cnv.xml files. Symbols (s*) DO have .cnv.xml files.
Step 3: Update Namespace & GUID in .fbt Files
<!-- BEFORE (source) -->
<FBType GUID="422cce07-335e-414d-823c-03c2d1ac0ef6"
Name="AnalogInput" Namespace="SE.App2CommonProcess">
<!-- AFTER (forked) -->
<FBType GUID="a59ec74d-736e-42ab-a3ff-de74c9003156"
Name="AnalogInput" Namespace="SE.ScadapackWWW">
Sub-block namespace rules:
| Block Type | Action |
|---|---|
| Forked blocks (in hierarchy) | Update to target namespace |
| Original library blocks | KEEP original namespace |
| Adapter interfaces | KEEP original namespace |
| DataTypes | KEEP original namespace |
<!-- MUST Update (forked blocks) -->
<FB Name="analogInputBaseExt" Type="AnalogInputBaseExt"
Namespace="SE.ScadapackWWW" />
<!-- MUST KEEP (original library blocks) -->
<FB Name="rawPv" Type="aISignal" Namespace="SE.App2Base" />
<FB Name="control" Type="analogInputLogic" Namespace="SE.App2CommonProcess" />
<Adapter Name="IPv" Type="IAnalog" Namespace="SE.App2Base" />
Step 4: Update .cfg File
The .cfg file links the CAT block to its HMI symbols. Update all paths:
<CAT Name="AnalogInputBase"
CATFile="AnalogInputBase\AnalogInputBase.fbt"
SymbolDefFile="..\HMI\AnalogInputBase\AnalogInputBase.def.cs"
SymbolEventFile="..\HMI\AnalogInputBase\AnalogInputBase.event.cs"
DesignFile="..\HMI\AnalogInputBase\AnalogInputBase.Design.resx"
DocFile="AnalogInputBase\AnalogInputBase.doc.xml"
Folder=".SignalProcessing.AnalogInput">
<HMIInterface Name="IThis" FileName="AnalogInputBase\AnalogInputBase_HMI.fbt">
<Symbol Name="fpDefault"
FileName="..\HMI\AnalogInputBase\AnalogInputBase_fpDefault.cnv.cs"
IsFaceplate="true">
<DependentFiles>..\HMI\AnalogInputBase\AnalogInputBase_fpDefault.cnv.Designer.cs</DependentFiles>
<DependentFiles>..\HMI\AnalogInputBase\AnalogInputBase_fpDefault.cnv.resx</DependentFiles>
</Symbol>
<Symbol Name="sDefault"
FileName="..\HMI\AnalogInputBase\AnalogInputBase_sDefault.cnv.cs">
<DependentFiles>..\HMI\AnalogInputBase\AnalogInputBase_sDefault.cnv.Designer.cs</DependentFiles>
<DependentFiles>..\HMI\AnalogInputBase\AnalogInputBase_sDefault.cnv.resx</DependentFiles>
<DependentFiles>..\HMI\AnalogInputBase\AnalogInputBase_sDefault.cnv.xml</DependentFiles>
</Symbol>
<!-- More symbols... -->
</HMIInterface>
<Plugin Name="Plugin=OfflineParametrizationEditor;..."
Project="SE.ScadapackWWW" <!-- UPDATE THIS -->
Value="AnalogInputBase\AnalogInputBase_CAT.offline.xml" />
</CAT>
Step 5: Update HMI Namespaces (CRITICAL – Complex Rules)
HMI files contain multiple categories of namespace references that require different handling:
Namespace Reference Categories
| Category | Pattern | Action | Example |
|---|---|---|---|
| Block-specific (this block) | {Lib}.Symbols.{Block}, {Lib}.Faceplates.{Block} |
UPDATE to target | SE.App2CommonProcess.Symbols.AnalogInputBase â SE.ScadapackWWW.Symbols.AnalogInputBase |
| Cross-block (forked block) | {Lib}.Symbols.{OtherForkedBlock} |
UPDATE if in forked set | When forking hierarchy, update AnalogInputBase refs in AnalogInput |
| Cross-block (not forked) | {Lib}.Symbols.{NonForkedBlock} |
KEEP original | Keep SE.App2CommonProcess.Symbols.Motor if Motor not forked |
| SupportClasses | {Lib}.SupportClasses |
ALWAYS KEEP | SE.App2CommonProcess.SupportClasses – contains shared utilities |
| Base library | SE.App2Base.* |
ALWAYS KEEP | SE.App2Base.Faceplates, SE.App2Base.Symbols, etc. |
| Framework | System.*, NxtControl.* |
ALWAYS KEEP | Framework namespaces never change |
Example: Using Directives in sDefault.cs
// From AnalogInputBase/sDefault.cs (decompiled)
// KEEP - Framework namespaces
using System;
using NxtControl.GuiFramework;
// KEEP - Base library (SE.App2Base)
using SE.App2Base.Faceplates;
using SE.App2Base.Graphics;
using SE.App2Base.SupportClasses;
using SE.App2Base.Symbols;
// UPDATE - Block-specific (this block is being forked)
using SE.App2CommonProcess.Faceplates.AnalogInputBase;
// â SE.ScadapackWWW.Faceplates.AnalogInputBase
// KEEP - SupportClasses (shared utilities, NOT block-specific)
using SE.App2CommonProcess.SupportClasses;
// Contains: AnalogInputUnit, MotorAppearance, ValveAppearance, etc.
namespace SE.App2CommonProcess.Symbols.AnalogInputBase;
// â namespace SE.ScadapackWWW.Symbols.AnalogInputBase;
Cross-Block References (Hierarchy Forks)
When forking a hierarchy (e.g., AnalogInput â AnalogInputBaseExt â AnalogInputBase), child blocks embed parent symbols:
// From AnalogInput/sDefault.cs (decompiled)
// UPDATE - Cross-block reference (AnalogInputBase IS in the forked set)
using SE.App2CommonProcess.Symbols.AnalogInputBase;
// â SE.ScadapackWWW.Symbols.AnalogInputBase
// Fully qualified type in field declaration
private SE.App2CommonProcess.Symbols.AnalogInputBase.sDefault analogFunction;
// â SE.ScadapackWWW.Symbols.AnalogInputBase.sDefault
// Instantiation
analogFunction = new SE.App2CommonProcess.Symbols.AnalogInputBase.sDefault();
// â new SE.ScadapackWWW.Symbols.AnalogInputBase.sDefault();
SupportClasses – Why They Must Be Preserved
The SupportClasses namespace contains library-wide utility classes shared across all blocks:
SE.App2CommonProcess.SupportClasses/
âââ AnalogInputUnit.cs # Used by AnalogInput symbols
âââ AnalogOutputUnit.cs # Used by AnalogOutput symbols
âââ MotorAppearance.cs # Used by Motor symbols
âââ ValveAppearance.cs # Used by Valve symbols
âââ PIDUnit.cs # Used by PID symbols
âââ BitExtensions.cs # Utility methods
âââ DynamicPropertyGrid.cs # UI helpers
âââ ... (60+ shared classes)
These classes are NOT part of any specific block and should NEVER have their references updated.
Files requiring namespace update:
{Block}.def.cs– Multiple namespaces (Faceplates and Symbols){Block}.event.cs– Multiple namespaces{Block}_*.cnv.cs– Single namespace per file (plus cross-block references)
What eae-fork Does vs What eae-cat Does
eae-fork (File Transformation)
| Task | Description |
|---|---|
| Copy IEC61499 files | .fbt, .cfg, .offline.xml, .opcua.xml |
| Copy HMI files | .def.cs, .event.cs, .cnv.*, .Design.resx |
| Update namespaces | In .fbt and .cs files |
| Generate new GUIDs | For all forked .fbt files |
| Update .cfg paths | SymbolDefFile, SymbolEventFile, etc. |
eae-cat (Project Registration)
| Task | Description |
|---|---|
| dfbproj registration | 3 ItemGroups (None, Compile, Content) |
| csproj registration | Compile, None, EmbeddedResource items |
| Folders.xml update | CAT folder entries |
| Validation | Verify block appears in library browser |
Why this separation?
- eae-fork handles file content transformation (namespace, GUID)
- eae-cat handles project structure (registration, dependencies)
- Each skill has clear, testable responsibilities
Commands
| Command | Description |
|---|---|
/eae-fork {Block} from {Lib} to {Target} |
Fork a block (asks about depth) |
/eae-fork --list {Lib} |
List blocks in source library |
/eae-fork --hierarchy {Block} |
Fork block with Base/BaseExt chain |
/eae-fork --with-deps {Block} |
Fork block with all dependencies |
/eae-fork --dry-run |
Show what would be forked |
Scripts
Detect Block Type (Orchestration)
The detect_block_type.py script examines source library files to determine block type for orchestration.
# Basic usage
python scripts/detect_block_type.py <block_name> <library_name>
# Examples
python scripts/detect_block_type.py AnalogInput SE.App2CommonProcess
# Output: Detected CAT block, sub-skill: eae-cat
python scripts/detect_block_type.py MyLogicFB SE.App2Base
# Output: Detected BASIC block, sub-skill: eae-basic-fb
# JSON output for automation
python scripts/detect_block_type.py AnalogInput SE.App2CommonProcess --json
# Verbose output with evidence
python scripts/detect_block_type.py AnalogInput SE.App2CommonProcess --verbose
Detection Logic:
| Block Type | Detection Criteria |
|---|---|
| CAT | Has .cfg file with <HMIInterface> elements |
| Composite | .fbt with Format="2.0" and <FBNetwork>, no <BasicFB> |
| Basic | .fbt with <BasicFB> element |
| Adapter | Has .adp file |
| DataType | Has .dt file |
Exit Codes:
| Code | Meaning |
|---|---|
| 0 | Success – type detected |
| 1 | Block not found |
| 2 | Unable to determine type |
Pre-flight Check
Validate prerequisites before fork operations to catch errors early.
# Basic usage
python scripts/preflight_check.py <block_name> <source_library> <target_library>
# Examples
python scripts/preflight_check.py AnalogInput SE.App2CommonProcess SE.ScadapackWWW
# Allow overwriting existing target block
python scripts/preflight_check.py --allow-overwrite AnalogInput SE.App2CommonProcess SE.ScadapackWWW
# JSON output for automation
python scripts/preflight_check.py --json Motor SE.App2CommonProcess SE.ScadapackWWW
What it checks:
| Check | Description |
|---|---|
| Source library | Library exists in standard locations |
| Source block | Block folder/files exist in source |
| Block type | Detects CAT/Composite/Basic/Adapter/DataType |
| Source files | Required files present for block type |
| Target library | Target exists in project |
| Target conflict | Block doesn’t already exist in target |
| dfbproj exists | Target has valid dfbproj file |
Exit Codes:
| Code | Meaning |
|---|---|
| 0 | Pre-flight passed, ready to fork |
| 1 | Error (missing arguments, etc.) |
| 10 | Pre-flight failed (prerequisites not met) |
| 11 | Target exists (use –allow-overwrite) |
Decompile HMI (Primary Script)
The decompile_hmi.py script extracts full HMI functionality from compiled library DLLs.
# Basic usage: decompile HMI for a single block
python scripts/decompile_hmi.py <source_lib> <block_name> <target_namespace> <output_dir>
# Example: Decompile AnalogInputBase HMI
python scripts/decompile_hmi.py SE.App2CommonProcess AnalogInputBase SE.ScadapackWWW \
"C:\Project\SE.ScadapackWWW\HMI"
# Hierarchy fork: update cross-references between forked blocks
python scripts/decompile_hmi.py SE.App2CommonProcess AnalogInput SE.ScadapackWWW ./output \
--forked-blocks AnalogInputBase AnalogInputBaseExt AnalogInput
# Use existing decompiled directory (skip re-decompilation)
python scripts/decompile_hmi.py SE.App2CommonProcess AnalogInput SE.ScadapackWWW ./output \
--decompiled-dir C:\temp\decompiled-hmi
# Keep decompiled files for inspection
python scripts/decompile_hmi.py SE.App2CommonProcess AnalogInput SE.ScadapackWWW ./output \
--keep-decompiled
Requirements:
- ILSpy CLI (
ilspycmd) – Install with:dotnet tool install -g ilspycmd - Python 3.8+
- Standard library only (no external dependencies)
Output Structure:
{output_dir}/{BlockName}/
âââ {BlockName}.def.cs # Faceplate/symbol partial class definitions
âââ {BlockName}.event.cs # Event argument classes
âââ {BlockName}.Design.resx # Design resources
âââ {BlockName}_fpDefault.cnv.cs # Faceplate main code
âââ {BlockName}_fpDefault.cnv.Designer.cs # InitializeComponent
âââ {BlockName}_fpDefault.cnv.resx # Faceplate resources
âââ {BlockName}_sDefault.cnv.cs # Symbol main code
âââ {BlockName}_sDefault.cnv.Designer.cs # InitializeComponent
âââ {BlockName}_sDefault.cnv.resx # Symbol resources
âââ {BlockName}_sDefault.cnv.xml # Symbol mapping (symbols only)
âââ ... (more symbols/faceplates)
Exit Codes:
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Error (library not found, decompilation failed, etc.) |
Fork Block
# Fork files and update namespaces (Steps 1-4 only)
python scripts/fork_block.py fork AnalogInput SE.App2CommonProcess SE.ScadapackWWW
# Fork with hierarchy
python scripts/fork_block.py fork AnalogInput SE.App2CommonProcess SE.ScadapackWWW --hierarchy
# List blocks
python scripts/fork_block.py list SE.App2CommonProcess
Validate Fork (Files Only)
# Validate namespace updates (NOT dfbproj registration)
python scripts/validate_fork.py SE.ScadapackWWW AnalogInput
Namespace Update Rules
MUST Update (Forked Blocks)
<!-- ROOT ELEMENT: Always update -->
<FBType Name="AnalogInput" Namespace="SE.ScadapackWWW">
<!-- SUB-BLOCKS that are ALSO forked: Update -->
<FB Name="analogInputBaseExt" Type="AnalogInputBaseExt"
Namespace="SE.ScadapackWWW" />
MUST KEEP (Original Library References)
<!-- Blocks from original libraries: Keep namespace -->
<FB Name="rawPv" Type="aISignal" Namespace="SE.App2Base" />
<!-- Adapter interfaces: Always keep original -->
<Adapter Name="IPv" Type="IAnalog" Namespace="SE.App2Base" />
<!-- DataTypes from original libraries: Keep -->
<VarDeclaration Name="Status" Type="Status" Namespace="SE.App2Base" />
Block Hierarchy Pattern
EAE blocks follow a three-tier hierarchy:
BlockBase â BlockBaseExt â Block
(core logic) (extended features) (complete)
Example:
AnalogInputBase â AnalogInputBaseExt â AnalogInput
Anti-Patterns
| Avoid | Why | Instead |
|---|---|---|
| Registering in dfbproj from eae-fork | Duplicates eae-cat logic | Delegate to eae-cat |
| Creating HMI stubs instead of decompiling | Stubs lack visual functionality | Use decompile_hmi.py |
| Changing original library namespace references | Breaks adapters | Keep original namespaces |
| Reusing source GUID | Conflicts with original | Generate new GUID |
| Not asking about fork depth | Wrong blocks forked | Always clarify with user |
| Updating SupportClasses references | Breaks shared utilities | Keep SE.{Lib}.SupportClasses |
Troubleshooting
| Issue | Cause | Solution |
|---|---|---|
| Block not visible in library | dfbproj not updated | Run eae-cat to register |
| HMI exceptions | Missing or invalid HMI files | Re-run decompile_hmi.py |
| Adapter errors | Wrong namespace | Keep adapter namespaces as SE.App2Base |
| Build errors | Incomplete hierarchy | Use --hierarchy flag |
| ILSpy not found | ilspycmd not installed | dotnet tool install -g ilspycmd |
| Empty symbol output | Block not in decompiled DLL | Check library path and block name |
| Missing SupportClasses | Namespace incorrectly updated | Keep SE.{Lib}.SupportClasses as-is |
Files Created by eae-fork
IEC61499 Files
| File | Changes |
|---|---|
{Block}.fbt |
Namespace, new GUID, sub-block references |
{Block}.cfg |
SymbolDefFile, SymbolEventFile, DesignFile, DocFile, Plugin Project= |
{Block}.doc.xml |
Copy as-is |
{Block}_HMI.fbt |
Namespace update, new GUID |
{Block}_CAT.offline.xml |
Copy as-is |
{Block}_CAT.opcua.xml |
Copy as-is |
{Block}_HMI.offline.xml |
Copy as-is |
{Block}_HMI.opcua.xml |
Copy as-is |
HMI Files (All copied and namespace-updated)
| File | Changes |
|---|---|
{Block}.def.cs |
Namespace update (multiple namespaces) |
{Block}.event.cs |
Namespace update (multiple namespaces) |
{Block}.Design.resx |
Copy as-is |
{Block}_fp*.cnv.cs |
Namespace update |
{Block}_fp*.cnv.Designer.cs |
Namespace update |
{Block}_fp*.cnv.resx |
Copy as-is |
{Block}_s*.cnv.cs |
Namespace update |
{Block}_s*.cnv.Designer.cs |
Namespace update |
{Block}_s*.cnv.resx |
Copy as-is |
{Block}_s*.cnv.xml |
Copy as-is |
Files NOT created by eae-fork (handled by eae-cat):
{Lib}.dfbproj– Project registration entries{Lib}.HMI.csproj– HMI project registration entriesGeneral/Folders.xml– CAT folder entries
HMI Decompilation Deep Dive
Why Decompilation is Required
Standard Schneider Electric libraries (SE.App2Base, SE.App2CommonProcess, etc.) ship with:
- Source files for IEC61499 blocks (
.fbt,.cfg, etc.) inFiles/directory - Compiled DLLs for HMI components in
HMI/directory - No source files for HMI symbols and faceplates
This means to fork a block with full HMI functionality, we must decompile the HMI DLL.
Decompilation Architecture
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â Library: C:\ProgramData\Schneider Electric\Libraries\ â
â SE.App2CommonProcess-25.0.1.5\ â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ¤
â Files/AnalogInputBase/ â HMI/SE.App2CommonProcess.HMI.dll â
â âââ AnalogInputBase.fbt â (COMPILED - contains all HMI) â
â âââ AnalogInputBase.cfg â â
â âââ ... â â
â (SOURCE AVAILABLE) â (MUST DECOMPILE) â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â
â¼ ILSpy Decompile
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â Decompiled Output (temp directory): â
â âââ SE.App2CommonProcess.Symbols.AnalogInputBase/ â
â â âââ sDefault.cs â Combined class file â
â â âââ sVertical.cs â
â â âââ sDisplayPv.cs â
â â âââ sInstanceName.cs â
â âââ SE.App2CommonProcess.Faceplates.AnalogInputBase/ â
â â âââ fpDefault.cs â Combined class file â
â â âââ fpParameter.cs â
â â âââ fpTrend.cs â
â âââ (resource files, mappings, etc.) â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â
â¼ Transform & Split
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â EAE-Compatible Output: â
â {Project}/SE.ScadapackWWW/HMI/AnalogInputBase/ â
â âââ AnalogInputBase.def.cs â Partial class definitions â
â âââ AnalogInputBase.event.cs â Event arguments â
â âââ AnalogInputBase.Design.resx â Design resources â
â âââ AnalogInputBase_sDefault.cnv.cs â Main code (namespace only) â
â âââ AnalogInputBase_sDefault.cnv.Designer.cs â InitializeComponent â
â âââ AnalogInputBase_sDefault.cnv.resx â Resources â
â âââ AnalogInputBase_sDefault.cnv.xml â Symbol mapping â
â âââ ... (more symbols/faceplates) â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
Class File Splitting
ILSpy produces single-file classes. EAE requires split files:
Decompiled (ILSpy output):
// sDefault.cs - COMBINED
using System;
using NxtControl.GuiFramework;
namespace SE.App2CommonProcess.Symbols.AnalogInputBase;
public class sDefault : SEAppLibHMISymbol
{
private AIFunctionName aIFunctionName;
private AnalogValue analogValue;
public sDefault()
{
InitializeComponent();
}
private void InitializeComponent()
{
this.aIFunctionName = new AIFunctionName();
this.analogValue = new AnalogValue();
this.aIFunctionName.Location = new Point(0, 0);
// ... 100+ lines of visual setup
}
}
EAE format (split):
// AnalogInputBase_sDefault.cnv.cs - MAIN
using NxtControl.GuiFramework;
using SE.App2Base.Symbols;
namespace SE.ScadapackWWW.Symbols.AnalogInputBase
{
public partial class sDefault : SEAppLibHMISymbol
{
public sDefault()
{
InitializeComponent();
}
}
}
// AnalogInputBase_sDefault.cnv.Designer.cs - DESIGNER
using System.Drawing;
using System.ComponentModel;
using NxtControl.Drawing;
using NxtControl.GuiFramework;
namespace SE.ScadapackWWW.Symbols.AnalogInputBase
{
partial class sDefault
{
private void InitializeComponent()
{
this.aIFunctionName = new AIFunctionName();
this.analogValue = new AnalogValue();
// ... full visual setup code
}
}
}
ILSpy Installation
# Install ILSpy CLI globally
dotnet tool install -g ilspycmd
# Verify installation
ilspycmd --version
# Common install location (Windows)
~/.dotnet/tools/ilspycmd.exe
Manual Decompilation (for Debugging)
# Decompile entire HMI DLL
ilspycmd "C:\ProgramData\Schneider Electric\Libraries\SE.App2CommonProcess-25.0.1.5\HMI\SE.App2CommonProcess.HMI.dll" -p -o C:\temp\decompiled
# Explore output structure
dir /s C:\temp\decompiled\SE.App2CommonProcess.Symbols.*
Related Skills
| Skill | Relationship |
|---|---|
| eae-cat | CALL AFTER FORK for CAT registration |
| eae-composite-fb | Call after fork for composite registration |
| eae-basic-fb | Call after fork for basic FB registration |
| eae-se-process | Find source blocks to fork |
| eae-runtime-base | Find sub-block types |
Changelog
v7.2.0 (Current)
- MAJOR ENHANCEMENT: Resume capability for interrupted forks
- NEW: Session state tracking (
.eae-fork-state.json) – Tracks completion progress - NEW:
load_session_state(),save_session_state(),clear_session_state()– Session management - NEW:
prompt_resume_or_restart()– Interactive resume/restart decision - HOW IT WORKS: Saves state after each successful block, allows resume on interruption
- BENEFIT: Never lose progress on large hierarchies (9+ blocks)
- USE CASE: System crashes, Ctrl+C interruptions, file access errors – all recoverable
- NEW: Session state tracking (
- MAJOR ENHANCEMENT: Dependency auto-detection
- NEW:
detect_dependencies.pyscript – Parses .cfg files to find SubCAT dependencies - NEW:
detect_block_hierarchy()– Detects Base â BaseExt â Full hierarchies - NEW:
parse_subcats_from_cfg()– Extracts SubCAT Type references from XML - HOW IT WORKS: Recursively analyzes .cfg files, builds complete dependency tree
- BENEFIT: Automatically suggests all blocks to fork (hierarchy + SubCATs)
- EXAMPLE:
MotorVsâ detects 3 hierarchy blocks + 6 SubCATs = 9 total blocks - USE CASE:
python detect_dependencies.py SE.App2CommonProcess MotorVs --include-hierarchy
- NEW:
- ENHANCEMENT: Pre-fork validation
- NEW:
validate_pre_fork()– Checks source blocks exist BEFORE manual fork - BENEFIT: Prevents wasted time in GUI if blocks don’t exist
- EXIT CODES: 0=ready, 10=validation failed
- NEW:
- ENHANCEMENT: Better error messages
- NEW: Custom exception classes (
ForkValidationError,NamespaceUpdateError,RegistrationError) - NEW:
print_helpful_error()– Contextual error messages with recovery suggestions - BENEFIT: Clear guidance on fixing errors instead of cryptic stack traces
- EXAMPLES: File permission errors â suggests closing editors and removing read-only
- NEW: Custom exception classes (
- UX IMPROVEMENTS:
- Clear session ID display on resume prompts
- Block mismatch detection (prevents resuming wrong fork)
- Stale session warnings (>24 hours old)
- Progress display (X/Y blocks completed)
- Dependency tree visualization (shows SubCAT relationships)
- TESTED: Validated on MotorVS fork (detected all 9 blocks correctly)
v7.1.0
- CRITICAL ENHANCEMENT: Transactional rollback protection
- NEW:
ForkTransactioncontext manager – Automatic backup/restore on failures - BENEFIT: Zero risk of project corruption from partial failures
- HOW IT WORKS: Backs up all blocks before changes, auto-restores on any error
- IMPACT: Protects against mid-execution crashes, file access errors, etc.
- NEW:
- CRITICAL FIX: UTF-8 encoding for international Windows systems
- FIXED: Unicode character errors (
â,â,âcaused crashes on CP1252 encoding) - SOLUTION: Force UTF-8 output + ASCII-safe symbols (
[OK],[ERROR],[SUCCESS]) - BENEFIT: Works reliably on French, German, Chinese, and all non-English Windows
- FIXED: Unicode character errors (
- DOCUMENTATION: Removed outdated v5.0 workflow section (was confusing)
- RELIABILITY: 100% failure-safe with automatic recovery
- TESTED: Validated on MotorVS fork (9 blocks, successful rollback testing)
v7.0.0
- MAJOR ENHANCEMENT: Fully automated cross-reference handling
- NEW:
update_cross_block_references()– Updates FB/SubCAT Namespace attributes for blocks in forked set - NEW:
update_hmi_cross_references()– Updates fully qualified type references in HMI Designer.cs files - NEW:
detect_source_namespace()– Automatically detects source namespace from .fbt files - IMPROVED: Workflow now single-command execution (no manual file editing)
- IMPROVED: Script infers forked blocks from arguments (no –forked-blocks flag needed)
- NEW:
- PERFORMANCE: ~15 seconds for hierarchy (vs 3+ minutes manual editing in v6.0)
- RELIABILITY: 100% systematic updates (no missed references)
- BENEFITS:
- â Zero manual file editing required
- â Automatic cross-block reference updates (IEC61499)
- â Automatic HMI cross-reference updates (Designer.cs)
- â Clear progress reporting and summary
- â Maintains all v6.0 benefits (perfect HMI files, simple workflow)
v6.0.0
- PARADIGM SHIFT: Hybrid manual/automated workflow
- Manual fork in EAE GUI â perfect HMI files (generated by EAE’s designer)
- Automated finalization â namespace updates + GUID generation + registration
- REMOVED: Decompilation complexity
- Deleted
decompile_hmi.py(no longer needed) - Deleted
generate_hmi_from_reflection.py(experimental, didn’t work) - Removed ILSpy CLI dependency
- Removed pythonnet dependency
- Deleted
- NEW:
finalize_manual_fork.pyscript- Validates manual fork completed in GUI
- Updates namespaces in .fbt and .cs files
- Generates new GUIDs
- Registers block in dfbproj/csproj
- ~140 lines vs 500+ lines of decompilation code
- IMPROVED: Reliability
- â 100% success rate (EAE-generated HMI files)
- â Simple & maintainable (namespace updates only)
- â Fast (~30 seconds per block)
- â User control (full visibility in GUI)
- BREAKING CHANGE: Workflow now requires manual fork in EAE GUI first
- Benefit: Perfect HMI files guaranteed
- Trade-off: User must perform fork in GUI (30 seconds)
- Net result: Simpler, more reliable overall workflow
v5.1.0
- CRITICAL FIX: Complete HMI file generation (SUPERSEDED by v6.0)
- Modified
fork_block.py::extract_decompiled_hmi()to call standalonedecompile_hmi.pyas subprocess - Now creates ALL required HMI files: .cnv.cs, .cnv.Designer.cs, .cnv.resx, .cnv.xml, .Design.resx
- Eliminated code duplication between fork_block.py and decompile_hmi.py
- Fixed EAE GUI errors “Unable to load Designer.cs/resx” files
- Modified
- CRITICAL FIX: Conditional aspmap.xml registration
- Modified
register_dfbproj.pyto check if aspmap.xml exists before adding to dfbproj - Only SE.App2CommonProcess blocks have aspmap.xml, SE.App2Base blocks don’t
- Eliminated “Solution Integrity” warnings for missing aspmap.xml files
- Modified
- IMPROVED: Files now match manual fork structure exactly
- TESTED: All symbols and faceplates open correctly in EAE GUI without errors
- NOTE: This version attempted to solve HMI generation via decompilation – v6.0 takes simpler approach
v5.0.0
- MAJOR: Automatic orchestration workflow
- eae-fork now detects block type and automatically calls appropriate registration sub-skill
- Users no longer need to manually run registration skills after forking
- Added
detect_block_type.pyscript for block type detection
- NEW: Block type detection examines source files to determine:
- CAT (has .cfg with HMIInterface)
- Composite (FBNetwork, no BasicFB)
- Basic (has BasicFB)
- Adapter (has .adp file)
- DataType (has .dt file)
- NEW: Orchestration routing to sub-skills:
- CAT â
/eae-cat --register-only - Composite â
/eae-composite-fb --register-only - Basic â
/eae-basic-fb --register-only - Adapter â
/eae-adapter --register-only - DataType â
/eae-datatype --register-only
- CAT â
- IMPROVED: Complete workflow in single command
v4.0.0
- MAJOR: Full HMI decompilation workflow
- Added
decompile_hmi.pyscript for extracting HMI from compiled DLLs - Uses ILSpy CLI (ilspycmd) for decompilation
- Splits decompiled classes into EAE format (.cnv.cs + .cnv.Designer.cs)
- Preserves full visual implementation (not stubs)
- Added
- NEW: Decompilation process:
- Locate HMI DLL in library folder
- Decompile using ILSpy to temp directory
- Find symbol/faceplate classes for the target block
- Extract InitializeComponent to Designer file
- Update namespaces with proper categorization rules
- Generate .resx and .cnv.xml files
- IMPROVED: Cross-block reference handling for hierarchy forks
--forked-blocksflag to specify all blocks being forked- Updates cross-references only for blocks in forked set
- REQUIREMENT: ILSpy CLI (
dotnet tool install -g ilspycmd)
v3.1.0
- CRITICAL FIX: Smart HMI namespace handling with proper reference categorization
- Block-specific namespaces (Symbols/Faceplates.{Block}): UPDATE if block is forked
- Cross-block references: UPDATE only if referenced block is in forked set
- SupportClasses: ALWAYS PRESERVE (library-wide shared utilities)
- Base library (SE.App2Base.*): ALWAYS PRESERVE
- Framework (System., NxtControl.): ALWAYS PRESERVE
- ENHANCED: Cross-block reference handling for hierarchy forks
- When forking AnalogInput hierarchy, AnalogInput’s reference to AnalogInputBase.sDefault is properly updated
- Fully qualified type references and instantiations are updated
- DOCUMENTED: Comprehensive namespace reference categories with examples
- IMPROVED: Better logging of preserved library references
v3.0.0
- CRITICAL FIX: HMI files must be COPIED from source, not generated
- Insight from manual fork analysis in EAE GUI
- HMI files contain complete implementations with designer code
- EXPANDED: eae-fork now handles Steps 1-5:
- Step 1: Copy IEC61499 files
- Step 2: Copy HMI files (NEW – from source library)
- Step 3: Update namespaces in .fbt files
- Step 4: Update .cfg file (expanded: all path attributes)
- Step 5: Update HMI namespaces in .cs files
- DOCUMENTED: Complete file list from manual fork analysis
- IEC61499 files: 8 file types
- HMI files: Up to 28 files per block (varies by symbols/faceplates)
- DOCUMENTED: Detailed .cfg file structure with all required attributes
- CLARIFIED: eae-cat handles project registration only (dfbproj, csproj, Folders.xml)
v2.1.0
- Clear separation of concerns between eae-fork and eae-cat
- Removed dfbproj registration from eae-fork (delegated to eae-cat)
v2.0.0
- Added fork depth user interaction question
- Added dfbproj registration (now moved to eae-cat)
- Added HMI file generation (now moved to eae-cat)
v1.0.0
- Initial release
- Basic file copy and namespace update