> ## Documentation Index
> Fetch the complete documentation index at: https://ahmed-walid.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Reverse XAML Islands?

> Hosting HWNDs inside XAML's visual tree

Hosting legacy Win32 content/window in XAML? Seems impossible, right? ***NO.***

The story started when I noticed [IDCompositionDevice::CreateSurfaceFromHwnd](https://docs.microsoft.com/en-us/windows/win32/api/dcomp/nf-dcomp-idcompositiondevice-createsurfacefromhwnd) function in the public docs of **DirectComposition.**

But I realized that we have a problem, this is for **DirectComposition** while XAML only *publicly* exposes **Windows.UI.Composition** objects

After some investigations on ***Windows.UI.Xaml.dll*** with IDA Pro, I noticed that XAML thankfully creates the **Windows.UI.Composition** device using **InteropCompositor** which allows you to cast **Windows.UI.Composition** objects into **DirectComposition** objects and vice versa. **GREAT!**

<br />

<Tip>
  You can read more about **InteropCompositor** in this great blogpost by **ADeltaX**: [InteropCompositor (and CoreDispatcher)](https://blog.adeltax.com/interopcompositor-and-coredispatcher/)
</Tip>

<br />

So the next problem was that the window has to be a layered (**WS\_EX\_LAYERED**) child (**WS\_CHILD**) window for ["cloak"ing](https://docs.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute) to work but we can't set our legacy window as a child window to the **ApplicationFrameWindow** window because it's not owned by our process but ***ApplicationFrameHost.exe.***

But *thankfully (again!)* the **CoreWindow** window is owned by our process so we can use it to be the parent of our legacy child window. **GREAT!**

So let's create our child window\...

```csharp expandable theme={null}
IntPtr hwnd = IntPtr.Zero;
List<IntPtr> childHwnds = new List<IntPtr>();

...

[StructLayout(LayoutKind.Sequential)]
internal unsafe struct WindowCompositionAttribData
{
    public _WINDOWCOMPOSITIONATTRIB Attribute;
    public int * Data;
    public int SizeOfData;
}

[DllImport("ext-ms-win-ntuser-private-l1-1-1.dll", SetLastError = true)]
internal static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WindowCompositionAttribData data);

public static unsafe void SetWindowCloak(IntPtr handle)
{
    int flag = 1;

    var data = new WindowCompositionAttribData();
    data.Attribute = _WINDOWCOMPOSITIONATTRIB.WCA_CLOAK; //17
    data.SizeOfData = sizeof(int);
    data.Data = & flag;

    SetWindowCompositionAttribute(handle, ref data);
    int result = Marshal.GetLastWin32Error();
    if (result != 0)
    {
        throw new Win32Exception(result);
    }
}

public static IntPtr EnableVisualStyles()
{
    StringBuilder sbSystemDir = new StringBuilder(256);
    GetSystemDirectory(sbSystemDir, 256);

    ACTCTX actCtx = new ACTCTX();
    actCtx.cbSize = Marshal.SizeOf(typeof(ACTCTX));
    actCtx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID |
				ACTCTX_FLAG_SET_PROCESS_DEFAULT |
				ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID;
    actCtx.lpSource = "shell32.dll";
    actCtx.wProcessorArchitecture = 0;
    actCtx.wLangId = 0;
    actCtx.lpAssemblyDirectory = sbSystemDir.ToString();
    actCtx.lpResourceName = (IntPtr) 124;
    IntPtr AcCtx = CreateActCtx(ref actCtx);
    ActivateActCtx(AcCtx, out IntPtr cookie);
    return cookie;
}

...

IntPtr coreWnd = ((ICoreWindowInterop) (object) CoreWindow.GetForCurrentThread()).WindowHandle;
IntPtr hInstance = Process.GetCurrentProcess().Handle;
string szAppName = "HelloWin";
WNDCLASS wndclass = new WNDCLASS();
wndclass.style = (uint)(ClassStyles.HorizontalRedraw | ClassStyles.VerticalRedraw);
wndclass.lpfnWndProc = (WndProc)((hWnd, message, wParam, lParam) =>
{
    IntPtr hdc;
    PAINTSTRUCT ps;
    RECT rect;
    switch ((WM) message)
    {
        case WM.PAINT:
        {
            hdc = BeginPaint(hWnd, out ps);
            GetClientRect(hWnd, out rect);
            FillRect(hdc, ref rect, GetStockObject(StockObjects.WHITE_BRUSH));
            EndPaint(hWnd, ref ps);
            return IntPtr.Zero;
            break;
        }
        case WM.DESTROY:
        {
            return IntPtr.Zero;
            break;
        }
        case WM.CREATE:
        {
            return IntPtr.Zero;
            break;
        }
    }
    return DefWindowProc(hWnd, (WM) message, wParam, lParam);
});

wndclass.hInstance = hInstance;
wndclass.lpszMenuName = null;
wndclass.lpszClassName = szAppName;
var regResult = RegisterClass(ref wndclass);

EnableVisualStyles();

hwnd = CreateWindowEx(
    (uint)(WindowStylesEx.WS_EX_LAYERED | WindowStylesEx.WS_EX_COMPOSITED),
    (ushort) new IntPtr((int)(uint) regResult),
    "The Hello Program", // window caption
    (uint) WindowStyles.WS_CHILD, // window style
    0, // initial x position
    0, // initial y position
    500, // initial x size
    500, // initial y size
    coreWnd, // parent window handle
    IntPtr.Zero, // window menu handle
    hInstance, // program instance handle
    IntPtr.Zero); // creation parameters
	
var ctls = new INITCOMMONCONTROLSEX(CommonControls.ICC_STANDARD_CLASSES | CommonControls.ICC_PROGRESS_CLASS);
InitCommonControlsEx(ref ctls);
ShowWindow(hwnd, (int) ShowWindowCommands.Normal);

SetWindowCloak(hwnd);

IntPtr hwndButton = CreateWindow(
    "BUTTON", // Predefined class
    "Hello from Comctl32!", // Button text 
    (uint) WindowStyles.WS_VISIBLE | (uint) WindowStyles.WS_CHILD, // Styles 
    0, // x position 
    0, // y position 
    200, // Button width
    100, // Button height
    hwnd, // Parent window
    IntPtr.Zero, // No menu.
    hInstance, 
    IntPtr.Zero); // Pointer not needed.
	
IntPtr hwndProg = CreateWindow(
    "msctls_progress32", // Predefined class
    null, // text 
    (uint) WindowStyles.WS_VISIBLE | (uint) WindowStyles.WS_CHILD | 0x08, // Styles 
    0, // x position 
    110, // y position 
    200, // width
    35, // height
    hwnd, // Parent window
    IntPtr.Zero, // No menu.
    hInstance, 
    IntPtr.Zero); // Pointer not needed.
	
SendMessage(hwndProg, (int)(WM.USER + 10), 1, 0); //Starts ProgressBar animation
childHwnds.Add(hwndButton);
```

<Note>
  **Notes:**

  * **WS\_EX\_COMPOSITED** extended style is required for the window to render
  * **ICoreWindowInterop** is defined in the public Windows SDK, you can copy the definition from there
  * **CreateWindowEx, InitCommonControlsEx, ShowWindow, SendMessage, ...** are native Windows functions, you can **DllImport** them from the corresponding dlls for them, I got most of definitions from [pinvoke.net](http://pinvoke.net), same with structs used in the code
</Note>

Now, let's create our Visual...

```csharp lines theme={null}
Compositor comp = Window.Current.Compositor;
IDCompositionDevice dcomp = (IDCompositionDevice)(object)comp;

IDCompositionVisual visualRaw = dcomp.CreateVisual();
visualRaw.SetOffsetX(0);
visualRaw.SetOffsetY(0);
visualRaw.SetContent(dcomp.CreateSurfaceFromHwnd(hwnd));

Visual visual = (Visual)visualRaw;
visual.Size = new Vector2(500, 500);

// "TheBox" is just a Viewbox control defined in page's XAML, you can use any XAML UIElement
ElementCompositionPreview.SetElementChildVisual(TheBox, visual);
```

Now, let's handle input *(the code sucks, I don't recommend using it)*...

```csharp expandable theme={null}
// We have to use CoreWindow pointer events because UIElement pointer events didn't work for some reasons...
CoreWindow coreWindow = CoreWindow.GetForCurrentThread();
coreWindow.PointerPressed += CoreWindow_PointerPressed;
coreWindow.PointerReleased += CoreWindow_PointerReleased;

...

private static int MAKELPARAM(int p, int p2)
{
	return ((p2 << 16) | (p & 0xFFFF));
}

...

private void CoreWindow_PointerReleased(CoreWindow sender, PointerEventArgs args)
{
	var ttv = this.TransformToVisual(TheBox);
	Point point = ttv.TransformPoint(args.CurrentPoint.Position);
	if (point.X > 0 && point.Y > 0)
	{
		SendMessage(hwnd, (uint) WM.LBUTTONUP, 0, MAKELPARAM((int) point.X, (int) point.Y));

		foreach(IntPtr wnd in childHwnds)
		{
			SendMessage(wnd, (uint) WM.LBUTTONUP, 0, MAKELPARAM((int) point.X, (int) point.Y));
		}
	}
}

private void CoreWindow_PointerPressed(CoreWindow sender, PointerEventArgs args)
{
	var ttv = this.TransformToVisual(TheBox);
	Point point = ttv.TransformPoint(args.CurrentPoint.Position);
	if (point.X > 0 && point.Y > 0)
	{
		SendMessage(hwnd, (uint) WM.LBUTTONDOWN, 0x0001, MAKELPARAM((int) point.X, (int) point.Y));

		foreach(IntPtr wnd in childHwnds)
		{
			SendMessage(wnd, (uint) WM.LBUTTONDOWN, 0x0001, MAKELPARAM((int) point.X, (int) point.Y));
		}
	}
}
```

<Tip>
  We can use [CoreIndependentInputSource](https://github.com/BreeceW/InteractionTrackerCrossProcessVisuals/pull/4) or **Windows::UI::Internal::Input::IInputSite** to receive input on the Visual itself so we don't need to use **CoreWindow** pointer events or transforming the **Point**, but let's leave that for another blogpost...
</Tip>

And here's the result!

<video controls className="w-full aspect-video rounded-xl" src="https://gist.github.com/user-attachments/assets/00f51b4f-bfd1-4793-afe9-a1d2e3b085f6" type="video/mp4" />
