This directory contains a sample Excel desktop test environment that combines two different add-in technologies in one solution:
- an Excel JavaScript add-in, responsible for a web-based custom task pane,
- an Excel-DNA add-in, responsible for native ribbon callbacks and UI Automation-based control of the JavaScript add-in UI.
The sample is designed to answer one specific question:
Can an Excel-DNA add-in running inside desktop Excel drive an Office JS custom task pane indirectly, even though the two add-ins are separate and do not share a direct runtime API?
The answer in this sample is "yes, via UI Automation", with the usual caveat that UI Automation is inherently more fragile than a direct supported integration path.
When the sample is loaded successfully into Excel, you get:
- a
Testing Testribbon group from the Office JS add-in, - a
Show Smiley Panebutton from that Office JS add-in, - a custom task pane titled
Testing JS Test Add-in, - a large smiling face emoji rendered inside the task pane,
- a
Testing DNAribbon tab from the Excel-DNA add-in, - a
Show JS Panebutton that uses UI Automation to invoke the Office JS ribbon button, - a
Hide JS Panebutton that uses UI Automation to click the task pane close button, - a
Dump UIA Treebutton that writes a filtered UI Automation snapshot to a text file and a new workbook.
This makes the sample useful both as:
- a runnable demo,
- a reference for adapting the UI Automation selectors to a real Excel add-in.
The two add-ins are independent:
- the Office JS add-in runs as a standard web add-in hosted from
https://localhost:3000, - the Excel-DNA add-in runs as a native
.xlladd-in targeting .NET Framework 4.8.
There is no direct call path between them.
Instead, the Excel-DNA add-in controls the Office JS add-in by interacting with Excel's user interface through Windows UI Automation:
- The Excel-DNA ribbon callback runs in-process in Excel.
- It locates Excel's main window handle through the Excel COM object model.
- It creates a UI Automation root from that window.
- It finds either:
- the Office JS ribbon button, or
- the Office JS task pane close button.
- It invokes that UI element through
InvokePattern.
This is deliberate. In many real-world hybrid add-in designs, you do not have a supported bridge from Excel-DNA into Office JS task pane lifetime management. UI Automation is one pragmatic fallback.
The parent directory contains:
- README.md: this document.
- Start-TestingExcelAddIns.ps1: convenience launcher intended to start the local web server, build/load the Excel-DNA add-in, and open both in one Excel session.
The Office JS add-in lives under OfficeJsAddIn.
Important files:
- manifest.xml
- server.js
- taskpane.html
- commands.html
The Excel-DNA add-in lives under ExcelDnaAddIn.
Important files:
- ExcelDnaAddIn.csproj
- RibbonController.cs
- OfficeJsPaneAutomation.cs
The Office JS add-in is a standard task pane add-in for Excel desktop.
Its manifest currently declares:
- display name:
Testing JS Test Add-in - provider name:
Local Test Environment - source location:
https://localhost:3000/src/taskpane.html - ribbon group label:
Testing Test - ribbon button label:
Show Smiley Pane
The key implementation choice is in manifest.xml:
- the ribbon button uses the built-in
ShowTaskpaneaction, - not a custom shared-runtime function.
That matters because:
ShowTaskpaneis reliable in this sample,- attempts to implement a true one-button show/hide toggle were unstable in this environment,
- the current sample therefore treats the Office JS command as "show only",
- the pane is closed either by Excel's
Xbutton or by the Excel-DNA add-in's UI Automation logic.
The visual content of the pane is intentionally simple. It exists to make task pane lifetime easy to validate:
- if the pane appears, hosting works,
- if the smiley is visible, the page loaded correctly,
- if the pane content is blocked, the certificate/server path is still wrong.
The Excel-DNA add-in contributes a custom ribbon tab called Testing DNA.
That ribbon is defined in RibbonController.cs. The main buttons are:
Show JS PaneHide JS PaneDump UIA Tree
The heavy lifting is in OfficeJsPaneAutomation.cs.
That file contains:
- the UI Automation selectors,
- the logic for locating Excel's UIA root,
- the search logic for ribbon controls and task pane controls,
- the UI tree dump logic,
- the threading boundary for deferred main-thread work.
Show JS Pane does not show the pane directly through an API. Instead, it:
- Gets the Excel main window handle from
ExcelDnaUtil.Application. - Builds a UI Automation root with
AutomationElement.FromHandle. - Selects the Excel
Hometab. - Finds the Office JS button named
Show Smiley Pane. - Invokes that control through UI Automation.
- Queues a best-effort switch back to the
Testing DNAtab usingExcelAsyncUtil.QueueAsMacro.
The queued follow-up matters because COM and UIA should not be driven from a background worker thread in this sample.
Hide JS Pane looks for the Office JS task pane chrome and tries to invoke the close button.
The relevant selectors are intentionally near the top of OfficeJsPaneAutomation.cs, so they are easy to retune:
JsShowRibbonButtonNameTaskPaneCloseButtonNameTaskPaneOptionsButtonNameTaskPaneWindowClassNameTaskPaneCloseButtonClassNameTaskPaneTitleCandidatesTaskPaneAnchorTexts
This is the main file to edit when adapting the sample to another ribbon layout, title string, Office channel, or localization.
Dump UIA Tree is a diagnostic tool for retuning UI Automation selectors.
It currently:
- traverses a filtered set of UI Automation nodes,
- writes a text dump into
%TEMP%, - creates a new workbook,
- writes the same filtered node list into a worksheet.
The filtering tries to keep the dump focused on:
- ribbon controls,
- NetUI/Mso task pane chrome,
- controls likely to matter for show/hide automation.
It intentionally avoids most worksheet and grid noise.
This sample should not access the Excel COM object model or UI Automation from worker threads.
Current rule:
- ribbon callbacks run on Excel's main thread,
- deferred follow-up work is returned to Excel's main thread via
ExcelAsyncUtil.QueueAsMacro, - the sample does not intentionally access COM/UIA from a background thread.
This is important because Excel COM and its UI surface are timing-sensitive, STA-oriented, and prone to subtle failure when touched from the wrong thread.
If you extend this sample, keep that rule.
To run the sample, you need:
- Windows,
- desktop Microsoft Excel,
- Node.js and npm,
- a .NET SDK with .NET Framework 4.8 targeting support,
- PowerShell 7 available as
pwsh.
There are two ways to run it:
- the convenience launcher from the parent directory,
- manual startup of each add-in.
From the parent directory, run:
pwsh -File .\Start-TestingExcelAddIns.ps1This script is intended to:
- install Office JS dependencies if needed,
- export and trust a localhost development certificate,
- register the Office JS manifest for sideloading,
- stop anything already listening on port
3000, - start the local Office JS HTTPS server,
- build the Excel-DNA project when needed,
- attach to an existing Excel instance or create one,
- register the Excel-DNA
.xll, - open the Office JS sideload workbook in that same Excel instance.
If you want to force an Excel-DNA rebuild:
pwsh -File .\Start-TestingExcelAddIns.ps1 -RebuildExcelDnaFrom OfficeJsAddIn:
npm install
npm startThen, from another shell in the same directory:
npm run sideloadThe local content should be served from:
https://localhost:3000
From ExcelDnaAddIn:
dotnet restore
dotnet buildThe Excel-DNA package now generates the .dna files during build output, rather than requiring a root project .dna file.
At the time of writing, the build output includes names like:
bin\Debug\net48\ExcelDnaAddIn-AddIn.xllbin\Debug\net48\ExcelDnaAddIn-AddIn64.xllbin\Debug\net48\publish\ExcelDnaAddIn-AddIn-packed.xllbin\Debug\net48\publish\ExcelDnaAddIn-AddIn64-packed.xll
Load the correct .xll for your Excel bitness through:
File > Options > Add-ins > Manage: Excel Add-ins > Go... > Browse...
Once both add-ins are loaded into the same Excel instance, test in this order:
- Click
Testing Test->Show Smiley Pane. - Confirm the Office JS task pane appears.
- Confirm the pane shows the smiling face content.
- Close the pane with the task pane
X. - Click
Testing DNA->Show JS Pane. - Confirm the pane appears again, this time because the Excel-DNA add-in invoked the Office JS ribbon control through UI Automation.
- Click
Testing DNA->Hide JS Pane. - Confirm the Excel-DNA add-in can close the pane through UI Automation.
- If any selector fails, click
Testing DNA->Dump UIA Treeand inspect the dump outputs.
If you are using this sample as a starting point for a real solution, the most likely places you will edit are:
Edit manifest.xml when you need to change:
- display name,
- ribbon group name,
- ribbon button name,
- task pane source page,
- URLs or assets.
Edit taskpane.html when you need to change:
- the pane content,
- styling,
- branding,
- any client-side UI for the web pane.
Edit OfficeJsPaneAutomation.cs when you need to change:
- ribbon button names,
- task pane title names,
- UI Automation class names,
- search depth,
- dump filtering,
- matching heuristics.
Edit RibbonController.cs when you need to change:
- the Excel-DNA tab layout,
- button labels,
- button callbacks,
- success/failure messaging.
Likely cause:
- the localhost HTTPS certificate chain is not trusted correctly.
What to do:
- rerun Start-TestingExcelAddIns.ps1,
- confirm
https://localhost:3000is reachable, - confirm Excel is not still holding onto an older broken registration.
Likely cause:
- the add-ins were launched independently instead of being attached to the same Excel instance.
What to do:
- close Excel fully,
- start again with Start-TestingExcelAddIns.ps1.
Likely causes:
- the ribbon label changed,
- the UI Automation tree differs on this Excel build,
- the Office JS command is not currently loaded on the expected tab.
What to do:
- run
Dump UIA Tree, - inspect the filtered output,
- adjust the constants and matching rules in OfficeJsPaneAutomation.cs.
Likely causes:
- the task pane title string changed,
- the title bar control hierarchy differs,
- the class names differ on this machine or Office build.
What to do:
- leave the pane visible,
- run
Dump UIA Tree, - update the task pane selectors in OfficeJsPaneAutomation.cs.
Likely causes:
- local HTTPS server is not running,
- certificate trust is incomplete,
- Excel opened a stale sideload registration.
What to do:
- verify
https://localhost:3000/src/taskpane.htmlresponds, - restart the local server,
- reopen Excel through the launcher.
Important note:
- the Excel-DNA build currently generates
*-AddIn.xllstyle names, - but any scripts or tooling that still assume the older
ExcelDnaAddIn64.xllnaming will need to be updated.
If the launcher stops finding the add-in output, fix the expected output path in Start-TestingExcelAddIns.ps1.
- The Office JS ribbon button is currently "show" only, not a robust toggle.
- UI Automation is inherently brittle compared with a direct supported API.
- Control names, class names, or tree shapes may vary by Excel version, Office channel, localization, DPI, or layout.
- The dump tool is diagnostic, not authoritative.
- The sample is optimized for clarity and testability, not for production-hardening.
This sample deliberately favors explicitness over abstraction.
You can see:
- exactly which ribbon labels are being targeted,
- exactly which task pane controls are being matched,
- exactly where the UI Automation traversal starts,
- exactly where to edit the selectors when adapting the sample.
That makes it a better diagnostic and learning project than a heavily abstracted one.
If you continue evolving this sample, the most useful next steps are:
- update the launcher to follow the current generated Excel-DNA output names,
- improve
Hide JS Paneby anchoring more precisely from the title area, - add supported-pattern details and parent-chain context to the dump output,
- make the UI Automation selector set configurable rather than hard-coded,
- add an integration note describing expected differences across Office builds.