Skip to content
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

Proxy IUnkown #14

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
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
5 changes: 5 additions & 0 deletions ShortDev.Uwp.FullTrust/ShortDev.Uwp.FullTrust.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="System.Reflection.Emit" Version="4.7.0" />
<PackageReference Include="System.Runtime.InteropServices.WindowsRuntime" Version="4.3.0">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand All @@ -49,4 +50,8 @@
</None>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ShortDev.Uwp.Internal\ShortDev.Uwp.Internal.csproj" />
</ItemGroup>

</Project>
71 changes: 71 additions & 0 deletions ShortDev.Uwp.FullTrust/ShortDev.Uwp.FullTrust/DelegateHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;

namespace ShortDev.Uwp.FullTrust
{
internal static partial class DelegateHelpers
{
private const MethodAttributes CtorAttributes = MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public;
private const MethodImplAttributes ImplAttributes = MethodImplAttributes.Runtime | MethodImplAttributes.Managed;
private const MethodAttributes InvokeAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual;
private static readonly Type[] _DelegateCtorSignature = new Type[] { typeof(object), typeof(IntPtr) };

static ModuleBuilder _moduleBuilder;
static DelegateHelpers()
{
AssemblyName assemblyName = new("ShortDev.DynamicDeleagtes");
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
_moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name);
}

public static Delegate CreateDelegate(MethodInfo method)
{
Type? type = CreateDelegateType(method);
if (type == null)
throw new NullReferenceException();

return Delegate.CreateDelegate(type, method);
}

public static Delegate CreateDelegate(object target, MethodInfo method)
{
Type? type = CreateDelegateType(method);
if (type == null)
throw new NullReferenceException();

return Delegate.CreateDelegate(type, target, method);
}

public static Type? CreateDelegateType(MethodInfo method)
{
Type declaringType = method.DeclaringType;
Assembly assembly = declaringType.Assembly;

string name = $"{assembly.FullName.Replace(".", "")}_{method.DeclaringType.FullName.Replace(".", "")}_{method.Name}_Sig";

return CreateDelegateType(
name,
method.GetParameters().Select((x) => x.ParameterType).ToArray(),
method.ReturnType
);
}

public static Type? CreateDelegateType(string name, Type[] parameters, Type returnType)
{
var cachedResult = _moduleBuilder.GetType(name);
if (cachedResult != null)
return cachedResult;

TypeBuilder builder = _moduleBuilder.DefineType(
name,
TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.AutoClass,
typeof(MulticastDelegate)
);
builder.DefineConstructor(CtorAttributes, CallingConventions.Standard, _DelegateCtorSignature).SetImplementationFlags(ImplAttributes);
builder.DefineMethod("Invoke", InvokeAttributes, returnType, parameters).SetImplementationFlags(ImplAttributes);
return builder.CreateTypeInfo();
}
}
}
161 changes: 152 additions & 9 deletions ShortDev.Uwp.FullTrust/Windows/UI/Xaml/FullTrustApplication.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
using ShortDev.Uwp.FullTrust.Xaml;
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using Windows.ApplicationModel.Activation;
using Windows.ApplicationModel.Core;
using Windows.System;
using Windows.UI.ViewManagement;
using System.Diagnostics;
using ShortDev.Uwp.FullTrust;
using System.Collections.Generic;

namespace Windows.UI.Xaml
{
Expand Down Expand Up @@ -57,22 +59,163 @@ public static void Start([In] ApplicationInitializationCallback callback, [In] X
thread.Join();
}

class C
{
public static void M()
{
Debugger.Break();
}
}

/// <summary>
/// Invokes <see cref="Application.OnLaunched(LaunchActivatedEventArgs)"/>
/// </summary>
static void InvokeOnLaunched()
static unsafe void InvokeOnLaunched()
{
var app = Current;
IntPtr pApplicationOverrides;
IntPtr* vtable;
{
IntPtr pUnk = Marshal.GetIUnknownForObject(Current);
Guid iid = typeof(IApplicationOverrides).GUID;
Marshal.ThrowExceptionForHR(Marshal.QueryInterface(pUnk, ref iid, out pApplicationOverrides));
vtable = *(IntPtr**)pApplicationOverrides;
}

var onLaunched = Marshal.GetDelegateForFunctionPointer<OnLaunchedProc>(vtable[7]);
Win32LaunchActivatedEventArgs launchArgs = new();
RCW rcw = new(Marshal.GetIUnknownForObject(launchArgs));
Marshal.ThrowExceptionForHR(onLaunched(pApplicationOverrides, rcw.GetIUnkown()));
GC.KeepAlive(launchArgs);
}

[ComVisible(true), UnmanagedFunctionPointer(CallingConvention.ThisCall)]
delegate int OnLaunchedProc([In] IntPtr @this, IntPtr args);

unsafe class RCW : IDisposable
{
#region HRESULT
const int S_OK = 0;
const int E_POINTER = -2147467261;
const int E_NOINTERFACE = unchecked((int)0x80004002);
#endregion

static readonly Guid IID_IUnkown = new("00000000-0000-0000-C000-000000000046");
static readonly Guid IID_IInspectable = new("AF86E2E0-B12D-4c6a-9C5A-D7AA65101E90");

public IntPtr PUnk { get; }

public RCW(IntPtr pUnk)
{
PUnk = pUnk;
}

public int QueryInterface(IntPtr @this, ref Guid riid, void** ppv)
{
if ((IntPtr)ppv == IntPtr.Zero)
return E_POINTER;

// *ppv = (void*)IntPtr.Zero;

if (riid == IID_IUnkown)
{
VtableRef vtable;
if (!_ppvs.TryGetValue(riid, out vtable))
{
vtable = new(3);
GenerateIUnkownVtable(vtable.Write());
_ppvs.Add(riid, vtable);
}
*ppv = (void*)vtable.Ptr;
return S_OK;
}

var hr = Marshal.QueryInterface(PUnk, ref riid, out var result);
*ppv = (void*)result;
return hr;
}

public IntPtr GetIUnkown()
{
IntPtr pv = IntPtr.Zero;
Guid iid = IID_IUnkown;
QueryInterface(IntPtr.Zero, ref iid, (void**)&pv);
return pv;
}

IntPtr[]? _unkVtable;
void GenerateIUnkownVtable(Span<IntPtr> vtable)
{
bool generate = _unkVtable == null;
_unkVtable = _unkVtable ?? new IntPtr[3];

if (generate)
{
_unkVtable[0] = Marshal.GetFunctionPointerForDelegate(DelegateHelpers.CreateDelegate(this, typeof(RCW).GetMethod("QueryInterface")));
_unkVtable[1] = Marshal.GetFunctionPointerForDelegate(DelegateHelpers.CreateDelegate(this, typeof(RCW).GetMethod("AddRef")));
_unkVtable[2] = Marshal.GetFunctionPointerForDelegate(DelegateHelpers.CreateDelegate(this, typeof(RCW).GetMethod("Release")));
}

vtable[0] = _unkVtable[0]; // QueryInterface
vtable[1] = _unkVtable[1]; // AddRef
vtable[2] = _unkVtable[2]; // Release
}

Win32LaunchActivatedEventArgs args_0 = new();
LaunchActivatedEventArgs args = args_0 as object as LaunchActivatedEventArgs;
app.GetType().GetMethod("OnLaunched", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(app, new[] { args });
#region Livetime
public int RefCount { get; private set; } = 0;
public int AddRef(IntPtr @this)
{
//RefCount++;
return S_OK;
}

return;
IApplicationOverrides applicationOverrides = (IApplicationOverrides)app;
applicationOverrides.OnLaunched(new Win32LaunchActivatedEventArgs());
public int Release(IntPtr @this)
{
//RefCount--;
//if (RefCount == 0)
// Dispose();
return S_OK;
}
#endregion

class VtableRef : IDisposable
{
public VtableRef(int size)
{
Size = size;
Ptr = Marshal.AllocHGlobal(IntPtr.Size);
ContentPtr = Marshal.AllocHGlobal(IntPtr.Size * size);
Marshal.WriteIntPtr(Ptr, ContentPtr);
}

public IntPtr Ptr { get; private set; }
public IntPtr ContentPtr { get; private set; }
public int Size { get; private set; }

public Span<IntPtr> Write()
=> new Span<IntPtr>((void*)ContentPtr, Size);

public void Dispose()
{
Marshal.FreeHGlobal(ContentPtr);
Marshal.FreeHGlobal(Ptr);
}
}

Dictionary<Guid, VtableRef> _ppvs = new();
public bool IsDisposed = false;
public void Dispose()
{
if (IsDisposed)
throw new ObjectDisposedException("RCW");

foreach (var ppv in _ppvs)
ppv.Value.Dispose();

GC.KeepAlive(this);
}
}

[ComVisible(true), ComDefaultInterface(typeof(ILaunchActivatedEventArgs))]
sealed class Win32LaunchActivatedEventArgs : ILaunchActivatedEventArgs, IActivatedEventArgs, IApplicationViewActivatedEventArgs, IPrelaunchActivatedEventArgs, IViewSwitcherProvider, ILaunchActivatedEventArgs2, IActivatedEventArgsWithUser
{
User? _currentUser;
Expand Down
4 changes: 4 additions & 0 deletions Test/UwpUI/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ public App()

protected override void OnLaunched(LaunchActivatedEventArgs args)
{
var t = args.GetType();
System.Diagnostics.Debug.Print(t.FullName);
ILaunchActivatedEventArgs args_0 = (args as ILaunchActivatedEventArgs);
var test = args_0.Arguments;
Frame frame = new Frame();
Window.Current.Content = frame;
frame.Navigate(typeof(MainPage));
Expand Down