Skip to content

[cmdpal][aot] Make app extension become AOT compatible #39325

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\..\Common.Dotnet.AotCompatibility.props" />
<PropertyGroup>
<RootNamespace>Microsoft.CmdPal.Ext.Apps</RootNamespace>
<Nullable>enable</Nullable>
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\WinUI3Apps\CmdPal</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

<ItemGroup>
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
GetPhysicallyInstalledSystemMemory
GlobalMemoryStatusEx
GetSystemInfo
CoCreateInstance
SetForegroundWindow
IsIconic
RegisterHotKey
@@ -13,7 +12,6 @@ SetFocus
SetActiveWindow
MonitorFromWindow
GetMonitorInfo
SHCreateStreamOnFileEx
CoAllowSetForegroundWindow
SHCreateStreamOnFileEx
SHLoadIndirectString
SHLoadIndirectString
IStream
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.IO.Abstractions;
using System.Linq;
using System.Runtime.InteropServices;
using System.Xml.Linq;
using Microsoft.CmdPal.Ext.Apps.Utils;
using Windows.Win32;
@@ -65,11 +66,18 @@ public void InitializeAppInfo(string installedLocation)
const uint noAttribute = 0x80;

var access = (uint)STGM.READ;
var hResult = PInvoke.SHCreateStreamOnFileEx(path, access, noAttribute, false, null, out IStream stream);
var hResult = Native.SHCreateStreamOnFileEx(path, access, noAttribute, false, IntPtr.Zero, out var streamPtr);

// S_OK
if (hResult == 0)
{
// create IStream from streamPtr
var stream = Marshal.GetTypedObjectForIUnknown(streamPtr, typeof(IStream)) as IStream;
if (stream == null)
{
return;
}

Apps = AppxPackageHelper.GetAppsFromManifest(stream).Select(appInManifest => new UWPApplication(appInManifest, this)).Where(a =>
{
var valid =
Original file line number Diff line number Diff line change
@@ -197,9 +197,10 @@ internal string ResourceFromPri(string packageFullName, string resourceReference
parsedFallback = prefix + "///" + key;
}

var outBuffer = new StringBuilder(128);
var outBuffer = new char[1024];

var source = $"@{{{packageFullName}? {parsed}}}";
var capacity = (uint)outBuffer.Capacity;
var capacity = (uint)outBuffer.Length;
var hResult = SHLoadIndirectString(source, outBuffer, capacity, IntPtr.Zero);
if (hResult != HRESULT.S_OK)
{
56 changes: 40 additions & 16 deletions src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Apps/Utils/Native.cs
Original file line number Diff line number Diff line change
@@ -5,24 +5,28 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Text;
using System.Runtime.InteropServices.Marshalling;
using Dia2Lib;

namespace Microsoft.CmdPal.Ext.Apps.Utils;

[SuppressMessage("Interoperability", "CA1401:P/Invokes should not be visible", Justification = "We want plugins to share this NativeMethods class, instead of each one creating its own.")]
public sealed class Native
public sealed partial class Native
{
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
public static extern int SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, int cchOutBuf, nint ppvReserved);
[LibraryImport("shell32.dll", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
public static partial int SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string path, nint pbc, ref Guid riid, [MarshalUsing(typeof(IShellItemMarshallerOut))] out IShellItem? shellItem);

[DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string path, nint pbc, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out IShellItem shellItem);
[LibraryImport("shlwapi.dll", StringMarshalling = StringMarshalling.Utf16)]
public static partial HRESULT SHLoadIndirectString(string pszSource, Span<char> pszOutBuf, uint cchOutBuf, nint ppvReserved);

[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
public static extern HRESULT SHCreateStreamOnFileEx(string fileName, STGM grfMode, uint attributes, bool create, System.Runtime.InteropServices.ComTypes.IStream reserved, out System.Runtime.InteropServices.ComTypes.IStream stream);

[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
public static extern HRESULT SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, uint cchOutBuf, nint ppvReserved);
[LibraryImport("shlwapi.dll", StringMarshalling = StringMarshalling.Utf16)]
public static partial int SHCreateStreamOnFileEx(
string pszFile,
uint grfMode,
uint dwAttributes,
[MarshalAs(UnmanagedType.Bool)] bool fCreate,
IntPtr pstmTemplate,
out IntPtr ppstm);

public enum HRESULT : uint
{
@@ -129,14 +133,14 @@ public enum SIGDN : uint
public interface IShellItem
{
void BindToHandler(
nint pbc,
[MarshalAs(UnmanagedType.LPStruct)] Guid bhid,
[MarshalAs(UnmanagedType.LPStruct)] Guid riid,
out nint ppv);
IntPtr pbc,
ref Guid bhid,
ref Guid riid,
out IntPtr ppv);

void GetParent(out IShellItem ppsi);

void GetDisplayName(SIGDN sigdnName, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName);
void GetDisplayName(SIGDN sigdnName, out IntPtr ppszName);

void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs);

@@ -154,4 +158,24 @@ public enum STGM : long
READWRITE = 0x00000002L,
CREATE = 0x00001000L,
}

[CustomMarshaller(typeof(IShellItem), MarshalMode.ManagedToUnmanagedOut, typeof(IShellItemMarshallerOut))]
public static partial class IShellItemMarshallerOut
{
public static IShellItem? ConvertToManaged(IntPtr unmanaged)
{
if (unmanaged == IntPtr.Zero)
{
return null;
}

var obj = Marshal.GetObjectForIUnknown(unmanaged);
return (IShellItem)obj;
}

public static void Free(IntPtr managed)
{
Marshal.FreeCoTaskMem(managed);
}
}
}
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Runtime.InteropServices;
using static Microsoft.CmdPal.Ext.Apps.Utils.Native;

namespace Microsoft.CmdPal.Ext.Apps.Utils;
@@ -40,7 +41,20 @@ public string GetLocalizedName(string path)
return string.Empty;
}

shellItem.GetDisplayName(SIGDN.NORMALDISPLAY, out var filename);
if (shellItem == null)
{
return string.Empty;
}

shellItem.GetDisplayName(SIGDN.NORMALDISPLAY, out var filenamePtr);

// get filename from ptr
var filename = Marshal.PtrToStringUni(filenamePtr);
Marshal.FreeCoTaskMem(filenamePtr);
if (filename == null)
{
return string.Empty;
}

_ = _localizationCache.TryAdd(lowerInvariantPath, filename);

Loading
Oops, something went wrong.