Skip to content

Commit

Permalink
Convert IFont and IFontDisp to CSWin32 (#8322)
Browse files Browse the repository at this point in the history
Converts IFont / IFontDisp to CSWin32. IFontDisp wasn't properly defined (wrong DISPIDs). I attemped to run my VB tests against the correct code to see if that fixed the test run problem, but alas, it did not. Including the VB tests (Skipped) to allow manual testing and allow investigating and vetting against further fixes that come as part of the modernization effort here.

This adds some tests for the other IFont usages. Additionally:

- Adds the interface definition for IDispatch (which CsWin32 omits) and a CCW
- Adds DynamicAxHost for testing AxHost with controls direct from assemblies
- Adds ComClasses/ComClassFactory for creating COM classes direct from assemblies
- Adds explicit converters to VARIANT and CY (currency format)
- Adds ToStringAndFree to BSTR
- Adds another overload for prop getting from IDispatch
- Moves code from ControlPaint to it's only usage in COM2FontConverter
  • Loading branch information
JeremyKuhne committed Dec 5, 2022
1 parent 2a329f0 commit 6277e50
Show file tree
Hide file tree
Showing 31 changed files with 772 additions and 333 deletions.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public sealed class QACONTAINER
public QACONTAINERFLAGS dwAmbientFlags;
public uint colorFore;
public uint colorBack;
public IFont? pFont;
public IFont.Interface? pFont;
public IntPtr pUndoMgr;
public uint dwAppearance;
public PInvoke.LCID lcid;
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@ public void Clear()
//
// If the VARTYPE is a VT_VECTOR, the contents are cleared as above and CoTaskMemFree is also called on
// cabstr.pElems.

//
// https://learn.microsoft.com/windows/win32/api/oleauto/nf-oleauto-variantclear#remarks
//
// - VT_BSTR (SysFreeString)
// - VT_DISPATCH / VT_UNKOWN (->Release(), if not VT_BYREF)

fixed (void* t = &this)
{
Expand Down Expand Up @@ -841,6 +844,32 @@ private static object ToVector(in CA ca, VARENUM vectorType)
private static Span<T> GetSpan<T>(Array arr)
=> MemoryMarshal.CreateSpan(ref Unsafe.AsRef<T>(Marshal.UnsafeAddrOfPinnedArrayElement(arr, 0).ToPointer()), arr.Length);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator bool(VARIANT variant)
=> variant.vt == VT_BOOL ? variant.data.boolVal != VARIANT_BOOL.VARIANT_FALSE : ThrowInvalidCast<bool>();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator short(VARIANT variant)
=> variant.vt == VT_I2 ? variant.data.iVal : ThrowInvalidCast<short>();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator BSTR(VARIANT variant)
=> variant.vt == VT_BSTR ? variant.data.bstrVal : ThrowInvalidCast<BSTR>();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator CY(VARIANT variant)
=> variant.vt == VT_CY ? variant.data.cyVal : ThrowInvalidCast<CY>();

public static explicit operator decimal(VARIANT variant) => variant.vt switch
{
VT_DECIMAL => variant.Anonymous.decVal.ToDecimal(),
VT_CY => decimal.FromOACurrency(variant.data.cyVal.int64),
_ => ThrowInvalidCast<decimal>(),
};

[MethodImpl(MethodImplOptions.NoInlining)]
private static T ThrowInvalidCast<T>() => throw new InvalidCastException();

internal partial struct _Anonymous_e__Union
{
internal partial struct _Anonymous_e__Struct
Expand Down
1 change: 1 addition & 0 deletions src/System.Windows.Forms.Primitives/src/NativeMethods.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"comInterop": {
"preserveSigMethods": [
"IAutoComplete2.SetOptions",
"IClassFactory.CreateInstance",
"IDispatch.Invoke",
"IFileDialog.Show",
"IFileDialog.GetResult",
Expand Down
17 changes: 16 additions & 1 deletion src/System.Windows.Forms.Primitives/src/NativeMethods.txt
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,23 @@ DestroyCursor
DestroyIcon
DestroyMenu
DestroyWindow
DestroyWindow
DISP_E_ARRAYISLOCKED
DISP_E_BADINDEX
DISP_E_BADPARAMCOUNT
DISP_E_BADVARTYPE
DISP_E_BADCALLEE
DISP_E_BUFFERTOOSMALL
DISP_E_DIVBYZERO
DISP_E_EXCEPTION
DISP_E_MEMBERNOTFOUND
DISP_E_NONAMEDARGS
DISP_E_NOTACOLLECTION
DISP_E_OVERFLOW
DISP_E_PARAMNOTFOUND
DISP_E_PARAMNOTOPTIONAL
DISP_E_TYPEMISMATCH
DISP_E_UNKNOWNINTERFACE
DISP_E_UNKNOWNLCID
DISP_E_UNKNOWNNAME
DISPATCH_FLAGS
DispatchMessage
Expand Down Expand Up @@ -128,6 +140,7 @@ ExtTextOut
FDAP
FILETIME
FillRect
FONTDESC
FormatMessage
FUNCDESC
FUNCFLAGS
Expand Down Expand Up @@ -267,6 +280,7 @@ HitTestThemeBackground
HWND_*
IAccessible
IAutoComplete2
IClassFactory
IClassFactory2
ICM_MODE
ICON_*
Expand Down Expand Up @@ -416,6 +430,7 @@ OLE_E_ADVISENOTSUPPORTED
OLE_E_INVALIDRECT
OLE_E_NOCONNECTION
OLE_E_PROMPTSAVECANCELLED
OleCreateFontIndirect
OleCreatePictureIndirect
OleFlushClipboard
OleInitialize
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,15 @@ public void Dispose()
}
}

/// <summary>
/// Converts the <see cref="BSTR"/> to string and frees it.
/// </summary>
public readonly string ToStringAndFree()
{
string result = ToString();
Dispose();
return result;
}

public bool IsNull => Value is null;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// 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 Windows.Win32.System.Com;

internal partial struct CY
{
// https://learn.microsoft.com/openspecs/windows_protocols/ms-oaut/5a2b34c4-d109-438e-9ec8-84816d8de40d

public static explicit operator decimal(CY value) => decimal.FromOACurrency(value.int64);
public static explicit operator CY(decimal value) => new() { int64 = decimal.ToOACurrency(value) };

public static explicit operator float(CY value) => (float)(value.int64 / 10000f);
public static explicit operator CY(float value) => new() { int64 = (long)(value * 10000) };
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// 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.

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using ComWrappers = Interop.WinFormsComWrappers;

namespace Windows.Win32.System.Com;

internal unsafe partial struct IDispatch : IVTable<IDispatch, IDispatch.Vtbl>
{
static void IVTable<IDispatch, Vtbl>.PopulateComInterfaceVTable(Vtbl* vtable)
{
vtable->GetTypeInfoCount_4 = &GetTypeInfoCount;
vtable->GetTypeInfo_5 = &GetTypeInfo;
vtable->GetIDsOfNames_6 = &GetIDsOfNames;
vtable->Invoke_7 = &Invoke;
}

[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })]
private static HRESULT GetTypeInfoCount(IDispatch* @this, uint* pctinfo)
=> ComWrappers.UnwrapAndInvoke<IDispatch, Interface>(@this, o => o.GetTypeInfoCount(pctinfo));

[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })]
private static HRESULT GetTypeInfo(IDispatch* @this, uint iTInfo, uint lcid, ITypeInfo** ppTInfo)
=> ComWrappers.UnwrapAndInvoke<IDispatch, Interface>(@this, o => o.GetTypeInfo(iTInfo, lcid, ppTInfo));

[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })]
private static HRESULT GetIDsOfNames(IDispatch* @this, Guid* riid, PWSTR* rgszNames, uint cNames, uint lcid, int* rgDispId)
=> ComWrappers.UnwrapAndInvoke<IDispatch, Interface>(@this, o => o.GetIDsOfNames(riid, rgszNames, cNames, lcid, rgDispId));

[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })]
private static HRESULT Invoke(
IDispatch* @this,
int dispIdMember,
Guid* riid,
uint lcid,
DISPATCH_FLAGS dwFlags,
DISPPARAMS* pDispParams,
VARIANT* pVarResult,
EXCEPINFO* pExcepInfo,
uint* pArgErr)
=> ComWrappers.UnwrapAndInvoke<IDispatch, Interface>(
@this,
o => o.Invoke(dispIdMember, riid, lcid, dwFlags, pDispParams, pVarResult, pExcepInfo, pArgErr));

[ComImport]
[Guid("00020400-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public unsafe interface Interface
{
[PreserveSig]
HRESULT GetTypeInfoCount(
uint* pctinfo);

[PreserveSig]
HRESULT GetTypeInfo(
uint iTInfo,
uint lcid,
ITypeInfo** ppTInfo);

[PreserveSig]
HRESULT GetIDsOfNames(
Guid* riid,
PWSTR* rgszNames,
uint cNames,
uint lcid,
int* rgDispId);

[PreserveSig]
HRESULT Invoke(
int dispIdMember,
Guid* riid,
uint lcid,
DISPATCH_FLAGS dwFlags,
DISPPARAMS* pDispParams,
VARIANT* pVarResult,
EXCEPINFO* pExcepInfo,
uint* pArgErr);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,17 @@ internal HRESULT GetProperty(
puArgErr: null);
}
}

/// <summary>
/// Get the specified <paramref name="dispId"/> property.
/// </summary>
internal VARIANT GetProperty(
uint dispId,
uint lcid = 0)
{
VARIANT variant = default;
GetProperty(dispId, &variant, lcid).ThrowOnFailure();
return variant;
}
}
}
Loading

0 comments on commit 6277e50

Please sign in to comment.