315 lines
11 KiB
Markdown
315 lines
11 KiB
Markdown
# ToonBoomActionManager.dll Class Analysis
|
|
|
|
This document describes the reverse-engineered class structures from `ToonBoomActionManager.dll`.
|
|
|
|
**IDA Database:** `RE/ToonBoomActionManager.dll.i64`
|
|
|
|
## Overview
|
|
|
|
ToonBoomActionManager.dll provides the action/command management infrastructure for Toon Boom applications (Harmony Premium, Storyboard Pro). It implements:
|
|
|
|
- **Responder Chain**: First responder and selection responder management
|
|
- **Menu System**: XML-based menu creation and management
|
|
- **Toolbar System**: Customizable toolbars with dynamic item insertion
|
|
- **Shortcut Management**: Keyboard shortcut handling
|
|
- **Action Triggering**: Command execution and validation
|
|
|
|
## Class Hierarchy
|
|
|
|
```
|
|
AC_Manager (abstract interface)
|
|
└── AC_ManagerImpl (concrete, inherits QObject)
|
|
|
|
AC_Object (abstract interface)
|
|
├── AC_Item (abstract interface)
|
|
├── AC_Separator (abstract interface)
|
|
└── AC_Toolbar (abstract, also inherits AC_Container, AC_Help)
|
|
└── AC_ToolbarImpl (concrete, inherits QToolBar)
|
|
|
|
AC_Container (abstract interface)
|
|
└── AC_ContainerImpl (concrete)
|
|
|
|
AC_Help (abstract interface)
|
|
|
|
AC_Responder (abstract interface)
|
|
└── AC_ResponderTemplate (concrete)
|
|
└── AC_ResponderTemplateWidget<T> (template)
|
|
```
|
|
|
|
---
|
|
|
|
## AC_Manager / AC_ManagerImpl
|
|
|
|
### Purpose
|
|
Central manager for the action/command system. Handles responder registration, menu/toolbar creation, and action triggering.
|
|
|
|
### Key Addresses
|
|
| Symbol | Address |
|
|
|--------|---------|
|
|
| AC_Manager vtable | `0x18004e508` |
|
|
| AC_ManagerImpl vtable (QObject) | `0x18004e750` |
|
|
| AC_ManagerImpl vtable (AC_Manager) | `0x18004e7c8` |
|
|
| AC_ManagerImpl::AC_ManagerImpl | `0x18000ef20` |
|
|
| AC_ManagerImpl::~AC_ManagerImpl | `0x18000f300` |
|
|
|
|
### Memory Layout (AC_ManagerImpl)
|
|
Total size: **0x158 (344 bytes)** on x64
|
|
|
|
| Offset | Size | Type | Field |
|
|
|--------|------|------|-------|
|
|
| +0x00 | 0x10 | | QObject base |
|
|
| +0x10 | 0x08 | vptr | AC_Manager vtable |
|
|
| +0x18 | 0x08 | void* | m_keywords (shared ptr data) |
|
|
| +0x20 | 0x08 | void* | m_keywords (continued) |
|
|
| +0x28 | 0x08 | void* | m_keywords (continued) |
|
|
| +0x30 | 0x01 | bool | m_trimShortcuts (init value) |
|
|
| +0x38 | 0x18 | | Responder name→list tree |
|
|
| +0x50 | 0x18 | | Menu tree |
|
|
| +0x68 | 0x08 | ptr | m_shortcutManager |
|
|
| +0x78 | 0x18 | QString | m_hoverId |
|
|
| +0x90 | 0x18 | QString | m_genericImage |
|
|
| +0xA8 | 0x18 | QString | m_toolbarCustomizeImage |
|
|
| +0xC0 | 0x18 | | Toolbar tree |
|
|
| +0xD8 | 0x18 | vector | m_registeredResponders |
|
|
| +0xF0 | 0x18 | vector | m_responderStack |
|
|
| +0x108 | 0x08 | ptr | m_menuBar |
|
|
| +0x118 | 0x08 | ptr | m_applicationResponder |
|
|
| +0x120 | 0x08 | ptr | m_selectionResponder |
|
|
| +0x128 | 0x08 | ptr | m_itemGenerator |
|
|
| +0x130 | 0x01 | bool | m_option_trimShortcuts |
|
|
|
|
### Key Methods
|
|
|
|
#### Responder Management
|
|
- `firstResponder()` - Returns top of responder stack (offset +248)
|
|
- `applicationResponder()` - Returns m_applicationResponder (offset +296)
|
|
- `registerResponder(responder, widget)` - Adds responder to registry; if `widget != nullptr`, inserts into a global widget map and calls `QObject::connect(widget, destroyed(QObject*), ...)` (see `docs/AC_Manager_registerResponder_QBitArrayCrash.md:1`)
|
|
- `setFirstResponder(responder)` - Sets active first responder
|
|
- `pushUp(responder)` - Stack manipulation (note: `pushOut` exists on the `AC_ManagerImpl` QObject vtable in this build, but is not part of the `AC_Manager*` vtable at `0x18004e7c8`)
|
|
|
|
#### Menu/Toolbar Creation
|
|
- `createMenuBar(element, parent)` - Create menu from XML
|
|
- `createToolbar(element, ids, mainWindow, area, name, owner)` - Create toolbar
|
|
- `loadMenus(path)` / `loadToolbars(path, ids)` - Load from file
|
|
|
|
#### AC_Manager Toolbar Vtable Slots (Verified in IDA)
|
|
- `loadToolbars(const QDomElement&, QList<QString>&)` - slot 46 (`+0x170`) at `0x180015940`
|
|
- `loadToolbars(const QString&, QList<QString>&)` - slot 47 (`+0x178`) at `0x180015f20` (parses file then forwards to slot 46)
|
|
- `toolbarElement(const QString&)` - slot 52 (`+0x1a0`) at `0x180016240` (returns `QDomElement` by value via MSVC x64 hidden sret out buffer)
|
|
- `updateToolbars()` - slot 53 (`+0x1a8`) at `0x180016350` (schedules `fireUpdateToolbars()` via `QTimer::singleShot(300, ...)`)
|
|
|
|
Note: `loadToolbars(...)` does not call `updateToolbars()` directly (verified by decompilation of `0x180015940` / `0x180015f20`).
|
|
|
|
Framework ABI note: `AC_Manager` is a vtable interface; `loadToolbars(const QDomElement&, ...)` must be declared before `loadToolbars(const QString&, ...)` to match slots 46/47. If your call appears to hit `updateToolbars()` or the wrong `loadToolbars` overload, suspect an ABI mismatch (wrong virtual order and/or wrong base pointer/vptr).
|
|
|
|
#### Action Triggering
|
|
- `trigger(responderIdentity, actionName, forEach)` - Execute action
|
|
- `performValidation(responderIdentity, actionName, enabled, checked)` - Validate action state
|
|
|
|
### Signals
|
|
```cpp
|
|
void firstResponderChanged();
|
|
void selectionResponderChanged();
|
|
void updateToolbarsSignal();
|
|
void updateToolbarsText();
|
|
```
|
|
|
|
---
|
|
|
|
## AC_Toolbar / AC_ToolbarImpl
|
|
|
|
### Purpose
|
|
Customizable toolbar with support for:
|
|
- Dynamic item insertion from XML
|
|
- Placeholder-based customization
|
|
- Configuration save/restore
|
|
- Context-sensitive help
|
|
|
|
### Key Addresses
|
|
| Symbol | Address |
|
|
|--------|---------|
|
|
| AC_ToolbarImpl vtable (QObject) | `0x180054c90` |
|
|
| AC_ToolbarImpl vtable (QPaintDevice) | `0x180054e70` |
|
|
| AC_ToolbarImpl vtable (AC_Toolbar) | `0x180054eb0` |
|
|
| AC_ToolbarImpl vtable (AC_Container) | `0x180054ef8` |
|
|
| AC_ToolbarImpl vtable (AC_Help) | `0x1800550f8` |
|
|
| AC_ToolbarImpl::AC_ToolbarImpl | `0x180032df0` |
|
|
| AC_ToolbarImpl::~AC_ToolbarImpl | `0x180033080` |
|
|
|
|
### Memory Layout (AC_ToolbarImpl)
|
|
Total size: **0x118 (280 bytes)** on x64
|
|
|
|
| Offset | Size | Type | Field |
|
|
|--------|------|------|-------|
|
|
| +0x00 | 0x28 | | QToolBar base (includes QObject, QPaintDevice) |
|
|
| +0x28 | 0x58 | AC_ContainerImpl | m_container (embedded) |
|
|
| +0x80 | 0x08 | vptr | AC_Toolbar vtable |
|
|
| +0x88 | 0x08 | vptr | AC_Container vtable |
|
|
| +0x90 | 0x08 | vptr | AC_Help vtable |
|
|
| +0x98 | 0x18 | QString | m_responderIdentity |
|
|
| +0xB0 | 0x18 | vector | m_defaultConfig |
|
|
| +0xC8 | 0x01 | bool | m_isCustomizable |
|
|
| +0xD0 | 0x08 | ptr | m_customizeButton |
|
|
| +0xD8 | 0x08 | ptr | m_unknown |
|
|
| +0xE0 | 0x08 | QObject* | m_owner |
|
|
| +0xE8 | 0x10 | QWeakPointer | m_mainWindow |
|
|
| +0xF8 | 0x04 | float | m_scaleFactor (default 1.0) |
|
|
| +0x100 | 0x18 | QString | m_translationContext |
|
|
|
|
### Interface Pointers
|
|
When you have an `AC_Toolbar*`:
|
|
- `QToolBar*` = `(char*)this - 128`
|
|
- `AC_ContainerImpl*` = `(char*)this - 88`
|
|
- Identity QString is at `(char*)this - 72`
|
|
|
|
### Key Methods
|
|
|
|
#### Item Management
|
|
- `insert(beforeObject, element)` - Insert item from XML
|
|
- `insertAtPlaceholder(placeholder, element)` - Insert at named placeholder
|
|
- `insertSeparator(beforeObject)` - Insert separator
|
|
- `removeObject(identity)` - Remove item by identity
|
|
- `clear()` - Remove all items
|
|
|
|
#### Configuration
|
|
- `config()` - Get current item order as QList<QString>
|
|
- `setConfig(list)` - Restore from saved configuration
|
|
- `defaultConfig()` - Get default item order
|
|
- `isDefaultConfig()` - Check if current matches default
|
|
|
|
#### Validation
|
|
- `validateContent()` - Update enabled/checked states
|
|
- `validateContentIfVisible()` - Only validate if toolbar is shown
|
|
- `updateSeparators()` - Hide separators adjacent to hidden items
|
|
|
|
### Signals
|
|
```cpp
|
|
void customized(QString identity);
|
|
```
|
|
|
|
---
|
|
|
|
## AC_ContainerImpl
|
|
|
|
### Purpose
|
|
Base container implementation for managing AC_Object children.
|
|
|
|
### Memory Layout
|
|
Total size: **0x58 (88 bytes)** on x64
|
|
|
|
| Offset | Size | Type | Field |
|
|
|--------|------|------|-------|
|
|
| +0x00 | 0x08 | vptr | AC_ContainerImpl vtable |
|
|
| +0x08 | 0x08 | ptr | m_manager (AC_ManagerImpl*) |
|
|
| +0x10 | 0x18 | QString | m_identity |
|
|
| +0x28 | 0x01 | bool | m_enabled |
|
|
| +0x29 | 0x01 | bool | m_isToolbar |
|
|
| +0x30 | 0x18 | vector | m_objects |
|
|
| +0x48 | 0x10 | | Placeholder tree |
|
|
|
|
---
|
|
|
|
## Enumerations
|
|
|
|
### AC_Result
|
|
```cpp
|
|
enum class AC_Result : int {
|
|
Handled = 0, // Action handled successfully
|
|
NotHandled = 1, // Action not handled by any responder
|
|
Error = 2 // Error during handling
|
|
};
|
|
```
|
|
|
|
### AC_ManagerOption
|
|
```cpp
|
|
enum class AC_ManagerOption : int {
|
|
TrimShortcuts = 0 // Whether to trim whitespace from shortcuts
|
|
};
|
|
```
|
|
|
|
### AC_Help::cshHelpType
|
|
```cpp
|
|
enum cshHelpType {
|
|
Type0 = 0,
|
|
Type1 = 1,
|
|
Type2 = 2,
|
|
Type3 = 3,
|
|
Type4 = 4,
|
|
ToolbarHelp = 5
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## XML Element Types
|
|
|
|
AC_ToolbarImpl::insert() handles these XML element types:
|
|
|
|
| Tag Name | Handler | Creates |
|
|
|----------|---------|---------|
|
|
| `item` | sub_1800363E0 | AC_ToolbarItemImpl |
|
|
| `menu` | sub_1800363E0 | AC_ToolbarItemImpl (menu button) |
|
|
| `multibutton` | sub_180037F30 | AC_ToolbarMultiButtonImpl |
|
|
| `combobox` | sub_1800395D0 | AC_ToolbarComboBox |
|
|
| `placeholder` | sub_18001B9F0 | Placeholder object |
|
|
| `separator` | sub_18003ABD0 | AC_ToolbarSeparatorImpl |
|
|
|
|
---
|
|
|
|
## Usage Patterns
|
|
|
|
### Getting AC_Manager Instance
|
|
```cpp
|
|
// Via PLUG_Services (from ToonBoomPlugInManager.dll)
|
|
AC_Manager* manager = PLUG_Services::getActionManager();
|
|
```
|
|
|
|
### Creating a Toolbar
|
|
```cpp
|
|
QList<QString> ids;
|
|
AC_Toolbar* toolbar = manager->createToolbar(
|
|
xmlElement, // QDomElement with toolbar definition
|
|
&ids, // Output: list of created item IDs
|
|
mainWindow, // QMainWindow to attach to
|
|
Qt::TopToolBarArea,// Toolbar area
|
|
"myToolbar", // Object name
|
|
owner // Owner QObject for cleanup
|
|
);
|
|
```
|
|
|
|
### Triggering an Action
|
|
```cpp
|
|
AC_Result result = manager->trigger(
|
|
"NetworkView", // Responder identity
|
|
"onActionZoomIn", // Action/slot name
|
|
false // Don't iterate all responders
|
|
);
|
|
```
|
|
|
|
### Validating an Action
|
|
```cpp
|
|
bool enabled, checked;
|
|
manager->performValidation("NetworkView", "onActionZoomIn", &enabled, &checked);
|
|
```
|
|
|
|
---
|
|
|
|
## Related Files
|
|
|
|
- `framework/include/toon_boom/ac_manager.hpp` - AC_Manager header
|
|
- `framework/include/toon_boom/toolbar.hpp` - AC_Toolbar header
|
|
- `framework/include/toon_boom/PLUG_Services.hpp` - Service access
|
|
|
|
---
|
|
|
|
## Methodology
|
|
|
|
This analysis was performed using:
|
|
1. IDA Pro decompilation of ToonBoomActionManager.dll
|
|
2. Vtable analysis to identify class hierarchies
|
|
3. Constructor/destructor analysis for memory layout
|
|
4. Cross-reference analysis for method identification
|
|
5. String analysis for signal/slot names
|
|
|
|
All offsets verified against x64 Windows builds of Toon Boom Harmony Premium.
|