Closed zadjii-msft closed 1 year ago
Elevation
[x] #1032 Mixed Elevation
- This is a hard problem, and I'm making no firm commitments that we'll be able to solve it for sure in 2.0.
- The goal of this deliverable is to find a safe way that we can support both elevated (High-IL) and unelevated (Medium-IL) tabs, panes, etc all in the same window.
- Ideally, if a user creates a new elevated tab from an unelevated window, then all the unelevated tabs would seamlessly appear in a new elevated HWND hosting both unelevated and elevated tabs simultaneously.
- Elevated connections can't be hosted in an unelevated HWND, because that allows for a trivial escalation-of-privilege vector utilizing the Terminal.
- This problem should arguably be investigated first. If this is something that's technically possible, it will certainly have an influence on the way the rest of these deliverables are architected.
- ❌ Resolution: This is not going to be technically achievable, unfortunately.
[ ] #632 Open a Profile as elevated
If the above is not achievable technically, then the user should still be able to specify a way to force a profile to open elevated.
If mixed elevation isn't possible:
If the current window isn't currently elevated, open a new window when someone's profile is marked "elevated: true"
If the current window is elevated, open in the same window.
What does this mean re. https://github.com/microsoft/terminal/issues/6893#issuecomment-657554241 and https://github.com/microsoft/terminal/issues/3581#issuecomment-581624314 etc.?
Will each window belong to a different process? Otherwise I don't understand what does "elevated window" even means.
And what if "elevation" actually mean "OTS elevation" rather than "AAM elevation", since the non-elevated user is not an admin? Currently at least that works. I hope the new model won't somehow break that.
@DHowett-MSFT @miniksa
Currently, yes, each terminal window is its own process. Each WT process has one window, so when you're running WT elevated, the window itself is elevated. Unfortunately, nothing in the new process model is going to have an affect on elevated drag drop. The team that owns the platform drag/drop APIs has specifically told us that drag/drop is unsupported in an elevated HWND.
Furthermore, we're not going to be messing with mixed elevation as a part of this effort anymore, because that turned out to be technically less possible than we hoped. So nothing about that story is about to change.
Maybe I'm missing something, but I just opened two elevated instances of WordPad, and dragged some text, a picture and an OLE Paint drawing from one to the other. And inside each document.
If by "platform" you mean UWP/Store/XAML/whatever-you-call-it-today, I just launched WinDbg Preview, installed from the Store, uses XAML and all that jazz, and managed to rearrange the windows in the elevated instance by dragging.
Specifically: "UWP XAML" (not WPF, which WinDbg Preview uses) uses the modern WinRT drag/drop APIs. Those APIs require a data broker process. That broker just doesn't work from an elevated context. Terminal, by way of it using "UWP XAML", is subject to this specific limitation.
About the Mixed Elevation part: Is there anything preventing possibility of a feature to launch medium integrity shells from high integrity wt instance? I know this is rather limited in comparison to the original plans, however should be much easier to support
to launch medium integrity shells from high integrity wt instance
I would like to hear what others think about this approach. This can be achieved running gsudo -i medium
on a wt tab or by creating a profile for it. There is also MediumPlus Integrity, which is higher than Medium (no medium process can tamper with it) but still hasn't admin acesss... (gsudo -i MediumPlus
)
Just as something that I saw mentioned as a comment on the spec, but not incorporated, I think the idea of having a separated elevated-settings.json
file makes a lot of sense as a counterpart to elevanted-state.json
. This gives a number of benefits
separated
elevated-settings.json
file makes a lot of sense as a counterpart toelevanted-state.json
.
I don't think this is a terrible idea. How do we deal with users who are currently using their unelevated settings in admin windows though? Would users need to maintain basically two copies of their settings file?
Maybe we only use the elevated-settings
file if we find it? If the file doesn't exist, then just fall back to the normal settings.
I guess it might make more sense if the elevated-settings
could be layered on top of settings.json
(a la #2303, #6502, #2933)
I wasn't thinking in terms of migration as much as qol, but I did also consider layering as an approach or adding a "create from unelevated settings" option in the settings UI. I didn't think thoroughly about the security implications (neither are technically worse than what exists now, but it could be better) so I didn't want to suggest something.
I'd say use settings.json as a base and override/merge values with anything in the elevated.json. Changed values or added sessions.
i agree, layering / overriding is the best choice, in either direction. although checking if elevated-settings.json exists, then using that and overriding with user one might make more sense so that
The file can be admin writeable only to help prevent malicious modification
is not pointless
\
dev/migrie/oop/2/endgame
📝 in dev/migrie/oop/2/endgame
Relevant diff (probably): 5c17603a94a76d47c4427f49493bca4eeb8fa774...81a5a736fef41bd90339c36a6cc4d7a339b6badf
_MakePane
usage:
_HandleSplitPane
_SplitPane
(__SplitPaneActiveTab
_)_OpenNewTab
_CreateNewTabFromPane
_CreateNewTabFromPane
call. Pane is not used afterwards._DuplicateTab
_CreateNewTabFromPane
_SplitTab
_SplitPane
(__SplitPaneOnTab
_)_OpenNewTerminalViaDropdown
_CreateNewTabFromPane
) or a new pane (_SplitPane
, (__SplitPaneActiveTab
_)), based on alt key state. _SplitPane
or _CreateNewTabFromPane
. This is the only one that uses it in post. AsyncSplitPane
or AsyncCreateNewTabFromPane
or something like that._OnNewConnection
_CreateNewTabFromPane
RundownAndExit
_core.UpdateSettings
on the UI thread when OOP is what gets us. \
dev/migrie/oop/2/wandavision
move-pane -w <id>
to move a pane/tab to another Terminal window. This will prove we can move panes without the whole instantiation of a new window process.
original diff at: in dev/migrie/oop/wandavision
(link to relevant diff from dev/migrie/oop/endgame
)
diff from endgame
: https://github.com/microsoft/terminal/compare/dev/migrie/oop/2/endgame...dev/migrie/oop/2/wandavision
TerminalPage::_MovePane
raises an event up, with the content guid of the current pane and a string describing the target windowWindowManager
to Monarch
, to ask the monarch to deal with this.AttachPaneToWindow
, with the target tab index and content guidTerminalPage::AttachPane
.RequestMoveContent(String window, String contentJson, Int tabIndex)
.
BuildStartupActions
in Pane
and in TabBase
accept a const bool asContent = false
parameter, to serialize with a content guidPane
TerminalTab
SettingsTab
std::vector<ActionAndArgs>
to a json blob. IVector
, presumably? Looks like in ApplicationState.h, we just use SetValueForKey(json, TabLayoutKey, val.TabLayout());
newTab
needs to be smart enough to look for a ContentGuid()
in the NewTerminalArgs
. If it finds one, do the content process attach instead.splitPane
.movePane(window)
. The tab-based code is MUCH easier to wrap your head around, and doesn't have the pane-wise edge cases.MovePane
to another window raises a RequestMoveContent
with the serialized form of the active pane.splitPane
...movePane(index=99999, window={window})
)MovePane
to another window raises a RequestMoveContent
with the serialized form of the active tab.newTab
...MoveContentArgs.tabIndex
is unused in this casemoveTab
to a window that doesn't exist, create a new window for that name, with that content? Is that possible?
contentProcess.Attached()
event. When the terminal move(Tab|Pane)
s, add a callback to Attached
. If we get that, we know someone else got it, and we can detach.After this is all done, we definitely could plop the string into a DataPackage and unwrap that to drop tabs.
As of 35c82d37f: (commented out, there are better gifs below)
I don't know if my issue related to the process model improvements, but I guess so. If I post it in a wrong thread, please move where needed.
Why don't you implement a per-tab execution policy for Windows Terminal? It would be very nice to have separate execution policies for different tabs, for everydays tasks Undefined policy is quite sufficient, but for some special development task like creating Python virtual environment I may need Unrestricted policy. It may be implemented by hotkey, or holding Ctrl-Shift on tab creation, whatever.
In the #632 you discussed why it is bad to have a mix of (non)elevated tabs, but here is a different thing. Changing execution policy and acquiring elevated permissions is not the same thing, and one can be done without another.
@Suncatcher Thanks for the request. It's a good idea! The catch here, though, is that the execution policy is a property of the thing that is running inside terminal, right? I think it's actually specifically a PowerShell concept... and I don't believe there's a way using the Windows API to influence the execution policy of any instances of PowerShell under a process tree using CreateProcess
(or its friends.) Even if there were, it wouldn't mean anything to cmd.exe
or Cygwin or nushell or yori, simply because they don't have an equivalent concept. Perl does, somewhat, have a restricted mode. I don't know if that's equivalent... and perl doesn't see much interactive use.
The easiest way to accomplish this today is going to be to add new profiles that use PowerShell native arguments to set the execution policy you want, and open those profiles from the New Tab dropdown menu.
As an example...
{
"commandline": "\"C:\\Program Files\\PowerShell\\7\\pwsh.exe\" -NoExit -Command \"Set-ExecutionPolicy Restricted -Scope Process\"",
"guid": "{d4207635-ac89-4c36-803f-7566ab0e243b}",
"hidden": false,
"icon": "🔐",
"name": "PowerShell (Restricted Policy)",
"startingDirectory": "%USERPROFILE%",
"background": "#330000"
},
thanks, didn't know this capability to set PS arguments per profile. Will use it.
Changes as of 2023
Everything is one process.
Proof-of-concept branch: https://github.com/microsoft/terminal/compare/main...dev/migrie/f/process-model-v3-test-0
Each of the headers here is an atomic PR plan, similar to the way I was doing the oop/2/
branches for PMv2. The goal being minimizing the individual code deltas.
dev/migrie/oop/3/foreword
- #14825Do this first, so that we can eventually have an AppLogic without necessitating a whole "window". Necessitated by the following train of thought:
TerminalApp::AppLogic
needs to get instantiated afterIslandWindow::Initialize
(currently called inAppHost::Initialize
) We need anAppLogic
to get at the settings to see if we want a window at all. So now we need a window to determine if we need to create a window. That's stupid. Can we avoid doing any XAML work before we get at the settings? Will that work?
AppLogic
into AppLogic
and TerminalWindow
(aka "window logic" aka "window model")dev/migrie/oop/3/ainulindale
#14843What if we started somewhere sane?
App
per process.AppHost
per thread.
AppLogic
per thread/window.::WindowEmperor
per process. Create it on startup.
AppLogic
, FYI. CreateNewWindowThread(WindowRequestedArgs)
method for the monarch to be able to request the creation of a new window thread (with a given ID / name / commandline / CWD). WindowThread
per window.
Peasant
for the window, the AppHost
, and the std::thread
.Peasant
, registers it with the Monarch
(who just requested it)Peasant
to AppHost
instead of letting AH create it. WindowEmperor
will look for an existing monarch
Emperor
will set monarch.WindowRequested({ &emperor, Emperor::CreateNewWindowThread})
WindowRequested
)AppLogic::_settings
was null after a language reload. Look into that. wtd -w 2
, then the process that hands off crashes when the App gets released. Maybe we could not?
wtd -- foo.exe
in another window is painfully jankydev/migrie/oop/3/valaquenta
ContentManager
for storing GUID -> ControlInteractivity
's
map<guid, IInspectable>
, and then QI to get the FrameworkElement
?~ NO BAD FWE's ARE XAML AND THREAD-BOUNDRemoting
could host it then...~ NO IT CAN'T FWE is XAMLControl
, since I think that's already included at a bunch of levels. TerminalApp
is a fine enough place. WindowExe
already includes that dll, and we don't need it below there. WindowEmperor
ContentManager
is instantiated... globally? and passed to each AppHost
, then down to the TerminalPage
. TermControl
adds a ctor where it takes an Interactivity
(and settings). ContentManager.CreateCore( settings )
Interactivity
to make a new TermControl
ContentManager.LookupCore( guid )
Interactivity
to make a new TermControl
Interactivity
definitely needs to re-instantiate its Dispatcher
Attached
event we had beforeconnection
to _MakePane
will be pre-filled in. We don't care about process boundaries for the connection, so uh, that's fine. __content
ticket_lock
? There's going to be multiple different UI threads that will ask for controls separately. <guid, weak_ref<IInspectable>>
. We'll use attached
event handlers to know when it's safe for the original TermControl
to go away.
dev/migrie/oop/3/quenta-silmarillion
#14866This would be the equivalent of dev/migrie/oop/2/wandavision
, see https://github.com/microsoft/terminal/issues/5000#issuecomment-1183694124
Monarch
needs to be able to move to a window based on ID, not just namemovePane(window)
Pane
might need to pre-init it's connection state from the control, because that might not be NotConnected
anymoremoveTab(window)
window
without a direction
, because right now it doesn'tstatic
members, so there's one per process, certainly on the wrong thread. Don't do that anymore
displayMarker
lambda, I believe (the stack was hard to interpret). This might be because the TermControl isn't actually _initialized
when it gets attached
auto transform{ marker.RenderTransform().as<Windows::UI::Xaml::Media::ScaleTransform>() };
crashed with a winrt::hresult_error: No such interface supported
control.Close()
in Pane::Shutdown
.
dev/migrie/oop/3/akallabeth
loki
changes.DataPackage
, so that we can't attempt to accept a d/d from another process. dev/migrie/oop/3/an-unexpected-party
In case I lose this over the long weekend:
sequenceDiagram
participant Source
participant Target
Note Left of Source: _onTabDragStarting
Source ->> Target: Drag tab
Note right of Target: _onTabStripDragOver
Target ->> Target: AcceptedOperation(DataPackageOperation::Move)
Source --> Target: Release mouse (to drop)
Note right of Target: _onTabStripDrop
Target -->> Source:
Note Left of Source: TabViewTabDragStartingEventArgs<br>.OperationCompleted
Note Left of Source: _onTabDroppedCompleted
You'll note: There's no message that the source gets prior to the target's TabStripDrop
to confirm that the drop worked. So, we can't detach the content from the source before the target would already take it.
FURTHERMORE
There's no event in the target after the source gets the acceptance. So there's no way for the target to wait for the source to detach first.
LASTLY
There's no way for the target to communicate back to the source. The e.Data()
is null on the target - only the DataView()
is accessible. That's immutable (obviously). And OperationCompleted
and TabDropCompleted
give you didly.
sequenceDiagram
participant Source
participant Target
participant Monarch
Note Left of Source: _onTabDragStarting
Source --> Source: stash dragged content
Source --> Source: pack window ID into DataPackage
Source ->> Target: Drag tab
Note right of Target: _onTabStripDragOver
Target ->> Target: AcceptedOperation(DataPackageOperation::Move)
Source --> Target: Release mouse (to drop)
Note right of Target: _onTabStripDrop
Target --> Target: get WindowID from DataPackage
Target -) Monarch: Request that WindowID sends content to us<br>RequestRecieveContent
Monarch -) Source: Tell to send content to Target.Id<br>RequestSendContent, SendContent
Source --> Source: detach our content
Source -) Monarch: RequestMoveContent(stashed, target.id)
Monarch -) Target: AttachContent(stashed)
# Target -->> Source:
# Note Left of Source: TabViewTabDragStartingEventArgs<br>.OperationCompleted
# Note Left of Source: _onTabDroppedCompleted
Pass the source's window ID in the package. When the target accepts it, have the target ask the monarch to ask the source to send its content to the target. Extremely dumb.
This API is particularly painful for the kinds of UI experiences we want.
TabItem
that's being dragged. So that it seems like that tab is already in the tab row. I don't think that's possible. TabView
? Forget about it. We'll need to basically just handle drag/drop there manually...
This scenario is tracking a number of enhancements we'd like to make to the fundamental process model of the Windows Terminal in v2.0. The following deliverables all have something to do with the way the Terminal is launched, or the way connections or instances are managed, and as such, the solution to any one of these areas should make sure to take into account the others.
Window / Session Managment
2080 is a draft spec for tearoff and default terminal app (below)
wt
in the current windowElevation
Default Terminal
Specs
TODOs
These are also tracked in https://github.com/microsoft/terminal/projects/5. This provides a nested list, to mentally track which things are dependent upon other things. This is basically a copy of a page of my notebook.
Window Management
* [x] Window Management, PR: #8898 * [ ] Next/Prev window keybindings * [x] Windowing Behavior, PR: #9118 * [ ] Smart `wt -w 0` handling * [x] Name windows on commandline * [x] `nameWindow` action (#9662) * [x] `openWindowRenamer` action (#9662) * [x] window-level toast for displaying window ID, action: `idenfifyWindows` (#9523) - Originally I thought I'd need generic toasts for this, but I'm gonna just do this first, and come back to generic toasts * [x] Quake Mode has been moved to #8888 * [x] New Window Action PR: #9208Tear Out
Currently planned state, notes:
See https://github.com/microsoft/terminal/issues/5000#issuecomment-1407110045 for the most up-to-date todo list. There were some dramatic changes to our plans in early 2023, which basically entirely obsoleted "Process Model 2" (where each termcontrol is its own process) in favor of "Process Model 3" (where all windows are all one process).
Original tear-out plans
* [ ] `wt.exe` accepts `--content guid` on the commandline to start in content mode. Additionally, Make the `Control` able to have the `Core` OOP. * these two were originally different bullet points, but I think they need to be combined into one singular PR. They don't make sense alone. - [x] in content process mode, it registers `ContentProcess` for that GUID with `CoRegisterClassObject` - [x] `ContentProcess::Initialize(IControlSettings, IConnection)` instantiates a new `ControlInteractivity` (in the content process) (if one hasn't already been initialized) - [x] `ContentProcess::RequestSwapChainHandle(pid)` will duplicate the handle if the pid is different - [x] `wt` properly tracks the lifetime of its content. When that's discarded by the last window process, we'll exit. - [x] Do the above line, but better. Now we're using a lock and an event, which is _ew_. Instead, we should do the Conhost `ExitThread()` thing on the main thread, and then ExitProcess() when the content process is dtor'd. - [x] Move all the chaos I've introduced in `main.cpp` into its own dedicated file/class or something. - [x] An embedding process needs a way to know that the content process is ready, better than a `Sleep(2000)` - A handle to an event is probably the cleanest way - have the window create the event, then pass the handle in `CreateProcess` & on the commandline to `wt --content {guid} --signal {handle}`, then have the content process set the event when it's ready. - 📝 in ~`dev/migrie/oop/the-whole-thing`~ `dev/migrie/oop/infinity-war` - [x] The `Connection` is made in the core - [x] When the Core signals that the swapchain changed, and the TermControl asks what the swapchain handle is, the Control passes in it's PID. If the PID isn't the same, `DuplicateHandle` the swapchain to that PID. - [x] The sample is updated with a version of the Control that's also OOP - [x] If the content process dies, the control needs to be able to display a message box. - [x] Make sure UIA signaling still works (`accevent.exe` in the SDK, `C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64`) - [x] Make sure that reading the contents of the buffer with Accessibility Insights still works - 💩 - `InteractivityAutomationPeer` extends `Windows.UI.Xaml.Automation.Peers.AutomationPeer`. But we're making the interactivity peer in the content process, not in the control layer. - When we construct the `IAP`, we throw instantly, because the `WUX..AutomationPeer` can't be created off the main thread. - How do we only expose the `WUX..AutomationPeer` via `TermControl`, but not `IAP`? - [x] The `_raiseContentDied` should display the error internal to the TermControl. Kinda like the renderer warning, but for this, we need to kill the `SwapChainPanel` too. - in ~`dev/migrie/oop/the-whole-thing`~ `dev/migrie/oop/infinity-war` - Relevant diff: 23a19c58181b489b10a2049232f23b033dbdab8d...5c17603a94a76d47c4427f49493bca4eeb8fa774 - [x] Add a velocity flag to gate behind dev builds only. Probably safe to just gate the `--content` flag for now. - [ ] Guard calls to `_interactivity`, `_core` in `TermControl`. Those objects might go out of scope at any moment, so pretty much all access needs to be try/caught. - we may want to do a function-level try, with a CATCH_RAISE_DIALOG() macro we write to raise the connection died notice. Might be the most minimal diff. - Could likely be a follow up to original PR. - There's a silly idea in `dev/migrie/oop/2/cptn-marvel`. I really hate it, it's a HUGE amount of churn. - [x] **There's a lot of debug spew** that makes me think the OOP core does something off the main thread. - BriAl and I synced - this is nothing to worry about. This is basically just COM logging "i'm about to increment the refcount" - Still trying to find a viable way to suppress that logging. - [x] What the hell did I do with the automation peer. Was what was in `main` correct? Revisit the original PRs for inspiration. - Did it ever work? there's seemingly no record of it working in 23a19c58181b489b10a2049232f23b033dbdab8d...5c17603a94a76d47c4427f49493bca4eeb8fa774 - #10051 has a fairly different implementation than the above diff - I may have simply forgotten that narrator / UIA uses exceptions for control flow, which makes debugging a pain - [x] `ControlCore::_IsClosing` TODO! - [x] `ContentProcess::RequestSwapChainHandle` tracelogging TODO! - [x] `TermControlAutomationPeer::GetLocalizedControlTypeCore` that string used to come from localized resources, it can't anymore. - [x] The `Control` properly manages the lifetime of the `HANDLE` duplicated to it. A `wil::unique_handle`? - [x] **IMPORTANT**: For whatever reason, when the second window attaches to the content, it renders basically nothing. Input gets sent just fine, but the output doesn't render.. Fixed in 7b3ca8332 - 📝 Now moved to [`dev/migrie/oop/2/infinity-war`](https://github.com/microsoft/terminal/compare/dev/migrie/oop/2/infinity-war) - 👀 in #12938 * [x] `TermControl`s need to have a local `TerminalSettings` instance. (Related: #7219) - What a shockingly simple oversight. We did all this work to get the connections in the same proc as the `TermControl`, we totally forgot the Settings. - [x] Make sure updating/changing settings works fine across processes - [x] Make sure previewing the color scheme still works. That works with some parent/child trickery that won't work OOP. - 📝 in `dev/migrie/oop/ragnarok` * [ ] Some misc cleanup before endgame: - [ ] `existingConnection` in `NewTab` was redundant / unused - [ ] `_SplitPane` renamed to `_SplitPaneActiveTab` etc. - [ ] Refactoring to allow the TerminalTab to be initialized without a control - [ ] Other stuff to, to minimize the diff - not started, in `dev/migrie/oop/2/black-widow` cause this one's not really consequential, is it now. * [ ] Make the app able to do the OOP instantiation. - Notes in https://github.com/microsoft/terminal/issues/5000#issuecomment-1137653858 * [x] Make the sample able to pop a control into a new window. - ✔️ in `dev/migrie/oop/the-whole-thing`. I didn't pop it into a new window, just made it so multiple windows could connect to the same one. * [ ] Defterm is out of proc. - [ ] DEFTERM: Incoming connections need to be tossed to the `ContentProcess`. Guh. - not started in `dev/migrie/oop/2/captain-falcon`. * [x] Tabs can be serialized to a json blob, with their tab & pane structure. - See #766, because this is highly relevant - This may have already been done for me by #10972 - [x] Serialize `TerminalTab`s - [x] Serialize `SettingsTab`s * [ ] `move-pane -wother notes
Just moving these lower in the body to make managing this doc easier
This is a pseudo design that Dustin and I discussed. There's a lot more work that needs to be done here, but I need to save this somewhere outside of a Teams chat history
``` --- struct TerminalControl: winrt::implements_4-30-21_:
I need to do the DX `HANDLE` thing before I can do the rest of the projection boundary. The projection boundary is in `dev/migrie/interactivity-projection-000`, which is almost done now. `dev/migrie/oop-scratch-4` has the final state of the OOP prototyping on this element. In that branch, * `HostAndProcess::CreateSwapChain` creates a swapchain with `DCompositionCreateSurfaceHandle`. * It attaches it to the `SwapChainPanel` with `ISwapChainPanelNative2::SetSwapChainHandle`. * It duplicates that handle to the content process, and calls `HostClass::ThisIsInsane` * Later on, the `HostClass` passes that handle to the `DxEngine` So we'll need to do basically that, but a little different, to handle all the actual edge cases we have.pre-1.10 era work
* [x] First, update `DxEngine` to accept the handle, but don't otherwise change anything (#10023) * ~~Then, change `TermControl` to create the handle with `DCompositionCreateSurfaceHandle`, hook it up to the `SwapChainPanel` with `ISwapChainPanelNative2::SetSwapChainHandle`.~~ - `DxEngine::_CreateDeviceResources` will need to trigger a callback in the `Core`, that will then ask the `TermControl` to create a new swapchain for it. - Wait no that's wrong. the `DxEngine` will always be making the swapchains, because it knows when it needs a new one. * [x] `DxEngine` will always make new swapchains, when needed, with `DCompositionCreateSurfaceHandle`. It'll raise an event when that happens. The `Core` will handle that, then raise an event the control will listen to. The `Control` will handle that event, then ask the `Core` for the new swapchain `HANDLE`, as a `uint64_t`. The Control will use that `uint64_t` to attach to the `SwapChainPanel` via `ISwapChainPanelNative2::SetSwapChainHandle`. - This is also the way it is in (#10023) - 👀 in #10023 * [x] Then we'll come back to the rest of the projection - 👀 in #10051 * [x] At this point, we should make a sample app that's just a grid with two spaces in it. One for an in-proc term control, and one for an out of proc one. We won't do the OOP one yet. - 👀 in #10067 * [x] Merge #10115 into #10067 * [x] Enable the Connection able to be created OOP from the rest of the TerminalPage. The content process will be the one to instantiate the connection. - [x] The Core is passed a (guid? String?) of a type of connection to spawn, and an `IConnectionSettings` object. The Core instantiates a type of connection based on that guid/string, and passes the `IConnectionSettings` from the window process to that new constructor. - [x] How does the azure connection work? I think that one's implemented in TerminalApp. If it's a String, we could pass the winrt name, `ITerminalConnection conn = RoCreateInstance("TerminalApp.AzureConnection"); conn.Create(iConnectionSettings);` , right? - No, turns out the Azure connection is in TerminalConnection. So this was actually fine the whole time. - Whatever, we're keeping the `RoGetActivationFactory` thing though, for future needs. - [ ] How does the debug tap work? - ~~Switch from `RoActivateInstance`&`Initialize` to `RoGetActivationFactory`~~ - > Even neglecting the Windows Runtime, this isn’t even possible in C++ or C#. - [x] Reattach event handlers that I disabled for performance's sake - [x] Merge #10115 into this branch, or into `dev/migrie/oop/connection-factory-rebase`, which is attempting to rebase these changes onto `dev/migrie/oop/sample-project` - 📝 in [`dev/migrie/oop/connection-factory`](https://github.com/microsoft/terminal/compare/dev/migrie/oop/the-whole-thing...dev/migrie/oop/connection-factory) * [x] 🦶 **PUNTED** ~Move the Core, the Interactivity, into `Core.dll`. We'll need that for:~ - We may not actually need this. It'd be _nice_ to not have to load _all_ the settings, but we could live with it.