>
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
You Might Also Like
Related Skills

coding-agent
Run Codex CLI, Claude Code, OpenCode, or Pi Coding Agent via background process for programmatic control.
openclaw
add-uint-support
Add unsigned integer (uint) type support to PyTorch operators by updating AT_DISPATCH macros. Use when adding support for uint16, uint32, uint64 types to operators, kernels, or when user mentions enabling unsigned types, barebones unsigned types, or uint support.
pytorch
at-dispatch-v2
Convert PyTorch AT_DISPATCH macros to AT_DISPATCH_V2 format in ATen C++ code. Use when porting AT_DISPATCH_ALL_TYPES_AND*, AT_DISPATCH_FLOATING_TYPES*, or other dispatch macros to the new v2 API. For ATen kernel files, CUDA kernels, and native operator implementations.
pytorch
skill-writer
Guide users through creating Agent Skills for Claude Code. Use when the user wants to create, write, author, or design a new Skill, or needs help with SKILL.md files, frontmatter, or skill structure.
pytorch
implementing-jsc-classes-cpp
Implements JavaScript classes in C++ using JavaScriptCore. Use when creating new JS classes with C++ bindings, prototypes, or constructors.
oven-sh
implementing-jsc-classes-zig
Creates JavaScript classes using Bun's Zig bindings generator (.classes.ts). Use when implementing new JS APIs in Zig with JSC integration.
oven-sh