Skip to content

Commit

Permalink
First stab at ComWrappers usage in the WPF
Browse files Browse the repository at this point in the history
This is minimal change which replace usage built-in COM for IThThreadMgr instance.
Having ComWrappers is important to make dotnet#3811 works.
  • Loading branch information
kant2002 committed May 20, 2022
1 parent 739d6d5 commit c21a0a6
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ internal void Uninitialize(bool appDomainShutdown)
{
if (_threadManager.Value != null)
{
Marshal.ReleaseComObject(_threadManager.Value);
((MS.Internal.WpfComWrappers.TfThreadMgrWrapper)_threadManager.Value).Dispose();
}
_threadManager = null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Threading;
using System.ComponentModel;
using System.Diagnostics;

// The SecurityHelper class differs between assemblies and could not actually be
// shared, so it is duplicated across namespaces to prevent name collision.
#if WINDOWS_BASE
using MS.Internal.WindowsBase;
#elif PRESENTATION_CORE
using MS.Internal.PresentationCore;
#elif PRESENTATIONFRAMEWORK
using MS.Internal.PresentationFramework;
#elif DRT
using MS.Internal.Drt;
#else
#error Attempt to use a class (duplicated across multiple namespaces) from an unknown assembly.
#endif
namespace MS.Win32
{
using Accessibility;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System;
using System.Security;
using System.Collections;
using System.IO;
using System.Text;
using Microsoft.Win32.SafeHandles;

using System.Runtime.InteropServices;

internal partial class UnsafeNativeMethods {
//------------------------------------------------------
Expand All @@ -43,7 +17,22 @@ internal partial class UnsafeNativeMethods {
#region public Methods

[DllImport("msctf.dll")]
internal static extern int TF_CreateThreadMgr(out ITfThreadMgr threadManager);
private static extern int TF_CreateThreadMgr(out IntPtr threadManager);

internal static int TF_CreateThreadMgr(out ITfThreadMgr threadManager)
{
var result = TF_CreateThreadMgr(out IntPtr threadManagerPtr);
if (result == 0)
{
threadManager = (ITfThreadMgr)MS.Internal.WpfComWrappers.Instance.GetOrCreateObjectForComInstance(threadManagerPtr, CreateObjectFlags.Unwrap);
}
else
{
threadManager = null;
}

return result;
}

/// <summary></summary>
[DllImport("msctf.dll")]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace MS.Internal;

using System;
using System.Runtime.InteropServices;
using static global::MS.Win32.UnsafeNativeMethods;

internal partial class WpfComWrappers
{
internal unsafe class TfThreadMgrWrapper : ITfThreadMgr
{
private readonly IntPtr _wrappedInstance;

internal TfThreadMgrWrapper(IntPtr wrappedInstance)
{
_wrappedInstance = wrappedInstance;
}

public void Dispose()
{
Marshal.Release(_wrappedInstance);
}

public void Activate(out int clientId)
{
fixed (int* pClientId = &clientId)
{
var result = ((delegate* unmanaged<IntPtr, int*, int>)(*(*(void***)_wrappedInstance + 3)))
(_wrappedInstance, pClientId);
if (result < 0)
{
Marshal.ThrowExceptionForHR(result);
}
}
}

public void Deactivate()
{
var result = ((delegate* unmanaged<IntPtr, int>)(*(*(void***)_wrappedInstance + 4)))
(_wrappedInstance);
if (result < 0)
{
Marshal.ThrowExceptionForHR(result);
}
}

public void CreateDocumentMgr(out ITfDocumentMgr docMgr)
{
IntPtr docMgrPtr = IntPtr.Zero;
var result = ((delegate* unmanaged<IntPtr, IntPtr*, int>)(*(*(void***)_wrappedInstance + 5)))
(_wrappedInstance, &docMgrPtr);
if (result < 0)
{
Marshal.ThrowExceptionForHR(result);
}

docMgr = (ITfDocumentMgr)Marshal.GetObjectForIUnknown(docMgrPtr);
}

public void EnumDocumentMgrs(out IEnumTfDocumentMgrs enumDocMgrs)
{
IntPtr enumDocMgrsPtr = IntPtr.Zero;
var result = ((delegate* unmanaged<IntPtr, IntPtr*, int>)(*(*(void***)_wrappedInstance + 6)))
(_wrappedInstance, &enumDocMgrsPtr);
if (result < 0)
{
Marshal.ThrowExceptionForHR(result);
}

enumDocMgrs = (IEnumTfDocumentMgrs)Marshal.GetObjectForIUnknown(enumDocMgrsPtr);
}

public void GetFocus(out ITfDocumentMgr docMgr)
{
IntPtr docMgrPtr = IntPtr.Zero;
var result = ((delegate* unmanaged<IntPtr, IntPtr*, int>)(*(*(void***)_wrappedInstance + 7)))
(_wrappedInstance, &docMgrPtr);
if (result < 0)
{
Marshal.ThrowExceptionForHR(result);
}

docMgr = (ITfDocumentMgr)Marshal.GetObjectForIUnknown(docMgrPtr);
}

public void SetFocus(ITfDocumentMgr docMgr)
{
IntPtr unknownPtr = Marshal.GetIUnknownForObject(docMgr);
var tfDocumentMgr = IID_ITfDocumentMgr;
var result = Marshal.QueryInterface(unknownPtr, ref tfDocumentMgr, out IntPtr docMgrPtr);
if (result < 0)
{
Marshal.ThrowExceptionForHR(result);
}

result = ((delegate* unmanaged<IntPtr, IntPtr, int>)(*(*(void***)_wrappedInstance + 8)))
(_wrappedInstance, docMgrPtr);
if (result < 0)
{
Marshal.ThrowExceptionForHR(result);
}
}

public void AssociateFocus(IntPtr hwnd, ITfDocumentMgr newDocMgr, out ITfDocumentMgr prevDocMgr)
{
IntPtr unknownPtr = Marshal.GetIUnknownForObject(newDocMgr);
var tfDocumentMgr = IID_ITfDocumentMgr;
var result = Marshal.QueryInterface(unknownPtr, ref tfDocumentMgr, out IntPtr newDocMgrPtr);
if (result < 0)
{
Marshal.ThrowExceptionForHR(result);
}

IntPtr prevDocMgrPtr = IntPtr.Zero;
result = ((delegate* unmanaged<IntPtr, IntPtr, IntPtr, IntPtr*, int>)(*(*(void***)_wrappedInstance + 9)))
(_wrappedInstance, hwnd, newDocMgrPtr, &prevDocMgrPtr);
if (result < 0)
{
Marshal.ThrowExceptionForHR(result);
}

prevDocMgr = (ITfDocumentMgr)Marshal.GetObjectForIUnknown(prevDocMgrPtr);
}

public void IsThreadFocus([MarshalAs(UnmanagedType.Bool)] out bool isFocus)
{
int isFocusNative;
var result = ((delegate* unmanaged<IntPtr, int*, int>)(*(*(void***)_wrappedInstance + 10)))
(_wrappedInstance, &isFocusNative);
if (result < 0)
{
Marshal.ThrowExceptionForHR(result);
}

isFocus = isFocusNative != 0;
}

public int GetFunctionProvider(ref Guid classId, out ITfFunctionProvider funcProvider)
{
IntPtr funcProviderPtr = IntPtr.Zero;
fixed (Guid* pClassId = &classId)
{
var result = ((delegate* unmanaged<IntPtr, Guid*, IntPtr*, int>)(*(*(void***)_wrappedInstance + 11)))
(_wrappedInstance, pClassId, &funcProviderPtr);
if (result < 0)
{
funcProvider = null;
return result;
}
}

funcProvider = (ITfFunctionProvider)Marshal.GetObjectForIUnknown(funcProviderPtr);
return 0;
}

public void EnumFunctionProviders(out IEnumTfFunctionProviders enumProviders)
{
IntPtr enumProvidersPtr = IntPtr.Zero;
var result = ((delegate* unmanaged<IntPtr, IntPtr*, int>)(*(*(void***)_wrappedInstance + 12)))
(_wrappedInstance, &enumProvidersPtr);
if (result < 0)
{
Marshal.ThrowExceptionForHR(result);
}

enumProviders = (IEnumTfFunctionProviders)Marshal.GetObjectForIUnknown(enumProvidersPtr);
}

public void GetGlobalCompartment(out ITfCompartmentMgr compartmentMgr)
{
IntPtr compartmentMgrPtr = IntPtr.Zero;
var result = ((delegate* unmanaged<IntPtr, IntPtr*, int>)(*(*(void***)_wrappedInstance + 12)))
(_wrappedInstance, &compartmentMgrPtr);
if (result < 0)
{
Marshal.ThrowExceptionForHR(result);
}

compartmentMgr = (ITfCompartmentMgr)Marshal.GetObjectForIUnknown(compartmentMgrPtr);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace MS.Internal;

using System;
using System.Collections;
using System.Runtime.InteropServices;

internal partial class WpfComWrappers : ComWrappers
{
// AA80E801-2021-11D2-93E0-0060B067B86E
private static readonly Guid IID_ITfThreadMgr = new Guid(0xAA80E801, 0x2021, 0x11D2, 0x93, 0xE0, 0x00, 0x60, 0xB0, 0x67, 0xB8, 0x6E);

// AA80E7F4-2021-11D2-93E0-0060B067B86E
private static readonly Guid IID_ITfDocumentMgr = new Guid(0xAA80E7F4, 0x2021, 0x11D2, 0x93, 0xE0, 0x00, 0x60, 0xB0, 0x67, 0xB8, 0x6E);

public static WpfComWrappers Instance { get; } = new WpfComWrappers();

protected override unsafe ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count)
{
throw new NotImplementedException();
}

protected override object CreateObject(IntPtr externalComObject, CreateObjectFlags flags)
{
var tfThreadMgrIID = IID_ITfThreadMgr;
if (Marshal.QueryInterface(externalComObject, ref tfThreadMgrIID, out var tfThreadMgrPtr) >= 0)
{
Marshal.Release(externalComObject);
return new TfThreadMgrWrapper(tfThreadMgrPtr);
}

throw new NotImplementedException();
}

protected override void ReleaseObjects(IEnumerable objects)
{
throw new NotImplementedException();
}
}
2 changes: 2 additions & 0 deletions src/Microsoft.DotNet.Wpf/src/WindowsBase/WindowsBase.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@
<Compile Include="MS\Internal\Verify.cs" />
<Compile Include="MS\Internal\WeakEventTable.cs" />
<Compile Include="MS\Internal\WeakReferenceKey.cs" />
<Compile Include="MS\Internal\WpfComWrappers.cs" />
<Compile Include="MS\Internal\WpfComWrappers.TfThreadMgrWrapper.cs" />
<Compile Include="OtherAssemblyAttrs.cs" />
<Compile Include="System\Collections\ObjectModel\WeakReadOnlyCollection.cs" />
<Compile Include="System\ComponentModel\CurrentChangedEventManager.cs" />
Expand Down

0 comments on commit c21a0a6

Please sign in to comment.