Summary
src/pages/reference-various.md → Custom Task Panes documents the CTP API but not the COM attribution a UserControl needs on .NET 6+. Without it, CustomTaskPaneFactory.CreateCustomTaskPane fails with a bare E_FAIL (0x80004005) and no diagnostic text.
This is already known — you answered it in issue #558 and in the group thread CustomTaskPaneFactory.CreateCustomTaskPane throws 'Unable to create specified ActiveX control':
You now need an explicit 'default interface' for your type - this will cause the class to implement IDispatch (if it is ComVisible).
The reference page doesn't carry that, so it's still reachable by reading the docs alone.
What I measured
Standalone add-in, no other dependency, ExcelDna.AddIn 1.9.0, SDK 10.0.400, Excel 16.0.20326.20112 x64 Click-to-Run Current Channel, Windows 11 25H2 26200.9168, not elevated, Defender only, Trust Center at defaults.
Control under test:
[ComVisible(true)]
public sealed class FixedLabelControl : UserControl
{
public FixedLabelControl() => Controls.Add(new Label { Text = "Repro Pane", AutoSize = true });
}
| Target |
Runtime |
Result |
net10.0-windows |
10.0.11 |
COMException, HRESULT -2147467259 (0x80004005) |
net7.0-windows |
7.0.7 |
COMException, HRESULT -2147467259 (0x80004005) |
Byte-identical source both times; only the TFM differed. Adding the documented attribution and changing nothing else:
[ComVisible(true)]
[Guid("...")]
public interface IFixedLabelControl { }
[ComVisible(true)]
[Guid("...")]
[ComDefaultInterface(typeof(IFixedLabelControl))]
public sealed class FixedLabelControl : UserControl, IFixedLabelControl { ... }
net10.0-windows then completed the full lifecycle — create, show, hide, delete, dispose — with no HRESULT.
Because the requirement splits .NET Framework from .NET Core rather than one .NET version from another, a net7-vs-net10 comparison can't discriminate it: both fail identically. That cost me a fair amount of bisecting before I found #558, which is really the motivation for this request.
Suggested addition
After the CreateCustomTaskPane example in the Custom Task Panes section:
.NET 6 and later: the control needs an explicit COM default interface. .NET Framework generated a class interface automatically, so a [ComVisible(true)] UserControl had a usable IDispatch; .NET Core and later do not, and CreateCustomTaskPane then fails with E_FAIL / "Unable to create specified ActiveX control".
public interface IMyUserControl { }
[ComVisible(true)]
[Guid("....")]
[ComDefaultInterface(typeof(IMyUserControl))]
public class MyUserControl : UserControl, IMyUserControl { }
Happy to open a PR against src/pages/reference-various.md if that's easier.
Separately, if it's ever cheap to do
ExcelCustomTaskPane.CreateCustomTaskPane already logs a helpful message for the UnauthorizedAccessException registry case. A comparable hint when ICTPFactory.CreateCTP throws E_FAIL — pointing at the default-interface requirement — would make this self-diagnosing. Entirely optional; the docs change is the ask.
Summary
src/pages/reference-various.md→ Custom Task Panes documents the CTP API but not the COM attribution aUserControlneeds on .NET 6+. Without it,CustomTaskPaneFactory.CreateCustomTaskPanefails with a bareE_FAIL(0x80004005) and no diagnostic text.This is already known — you answered it in issue #558 and in the group thread CustomTaskPaneFactory.CreateCustomTaskPane throws 'Unable to create specified ActiveX control':
The reference page doesn't carry that, so it's still reachable by reading the docs alone.
What I measured
Standalone add-in, no other dependency,
ExcelDna.AddIn1.9.0, SDK 10.0.400, Excel 16.0.20326.20112 x64 Click-to-Run Current Channel, Windows 11 25H2 26200.9168, not elevated, Defender only, Trust Center at defaults.Control under test:
net10.0-windowsCOMException, HRESULT-2147467259(0x80004005)net7.0-windowsCOMException, HRESULT-2147467259(0x80004005)Byte-identical source both times; only the TFM differed. Adding the documented attribution and changing nothing else:
net10.0-windowsthen completed the full lifecycle — create, show, hide, delete, dispose — with no HRESULT.Because the requirement splits .NET Framework from .NET Core rather than one .NET version from another, a net7-vs-net10 comparison can't discriminate it: both fail identically. That cost me a fair amount of bisecting before I found #558, which is really the motivation for this request.
Suggested addition
After the
CreateCustomTaskPaneexample in the Custom Task Panes section:Happy to open a PR against
src/pages/reference-various.mdif that's easier.Separately, if it's ever cheap to do
ExcelCustomTaskPane.CreateCustomTaskPanealready logs a helpful message for theUnauthorizedAccessExceptionregistry case. A comparable hint whenICTPFactory.CreateCTPthrowsE_FAIL— pointing at the default-interface requirement — would make this self-diagnosing. Entirely optional; the docs change is the ask.