diff --git a/Package/Excel-DNA.Interop/Excel-DNA.Interop.nuspec b/Package/Excel-DNA.Interop/Excel-DNA.Interop.nuspec
index bf503542..ec6112e2 100644
--- a/Package/Excel-DNA.Interop/Excel-DNA.Interop.nuspec
+++ b/Package/Excel-DNA.Interop/Excel-DNA.Interop.nuspec
@@ -2,7 +2,7 @@
Excel-DNA.Interop
- 15.0.1
+ 16.0.0
Excel-DNA - Primary Interop Assemblies for Excel
Excel-DNA Contributors
excel-dna
@@ -10,15 +10,17 @@
images\ExcelDna-nu.png
MIT
+ README.md
false
This package is deprecated, and has been replaced by ExcelDna.Interop - https://www.nuget.org/packages/ExcelDna.Interop/.
Provides a selection of Excel Primary Interop Assemblies
Excel Interop PIA ExcelDna
-
+
+
diff --git a/Package/Excel-DNA.Interop/README.md b/Package/Excel-DNA.Interop/README.md
new file mode 100644
index 00000000..e31d9c7f
--- /dev/null
+++ b/Package/Excel-DNA.Interop/README.md
@@ -0,0 +1,5 @@
+# Excel-DNA.Interop
+
+This package is deprecated. Use [ExcelDna.Interop](https://www.nuget.org/packages/ExcelDna.Interop/) instead.
+
+The dependency on `ExcelDna.Interop` supplies the Microsoft Office primary interop assemblies used by Excel-DNA add-ins.
diff --git a/Package/ExcelDna.Interop.Dao/ExcelDna.Interop.Dao.nuspec b/Package/ExcelDna.Interop.Dao/ExcelDna.Interop.Dao.nuspec
index 57845669..89f34feb 100644
--- a/Package/ExcelDna.Interop.Dao/ExcelDna.Interop.Dao.nuspec
+++ b/Package/ExcelDna.Interop.Dao/ExcelDna.Interop.Dao.nuspec
@@ -8,6 +8,7 @@
http://excel-dna.net
images\ExcelDna-nu.png
MIT
+ README.md
false
Provides a local copy of the Microsoft.Office.Interop.Access.Dao.dll primary interop assembly from Microsoft Office.
Provides the Primary Interop Assembly for the Access DAO library.
@@ -24,5 +25,6 @@
+
diff --git a/Package/ExcelDna.Interop.Dao/README.md b/Package/ExcelDna.Interop.Dao/README.md
new file mode 100644
index 00000000..f7c33225
--- /dev/null
+++ b/Package/ExcelDna.Interop.Dao/README.md
@@ -0,0 +1,7 @@
+# ExcelDna.Interop.Dao
+
+This package provides a local copy of the `Microsoft.Office.Interop.Access.Dao.dll` primary interop assembly for the Microsoft Access DAO library.
+
+The assembly is available for .NET Framework 4.5.2 and `net6.0-windows7.0` projects. The package configures C# and Visual Basic projects to embed the interop types and not copy the assembly to the output directory. F# projects are excluded from that build behavior.
+
+For Excel-DNA documentation, see [excel-dna.net](https://excel-dna.net/).
diff --git a/Package/ExcelDna.Interop/ExcelDna.Interop.nuspec b/Package/ExcelDna.Interop/ExcelDna.Interop.nuspec
index 1c583976..79e4c8c6 100644
--- a/Package/ExcelDna.Interop/ExcelDna.Interop.nuspec
+++ b/Package/ExcelDna.Interop/ExcelDna.Interop.nuspec
@@ -8,6 +8,7 @@
http://excel-dna.net
images\ExcelDna-nu.png
MIT
+ README.md
false
Provides a local copy of the Primary Interop Assemblies from Microsoft Office: Microsoft.Office.Interop.Excel.dll, Office.dll, Microsoft.Vbe.Interop.dll.
Provides a selection of Excel Primary Interop Assemblies
@@ -28,5 +29,6 @@
+
diff --git a/Package/ExcelDna.Interop/README.md b/Package/ExcelDna.Interop/README.md
new file mode 100644
index 00000000..eae0d1bd
--- /dev/null
+++ b/Package/ExcelDna.Interop/README.md
@@ -0,0 +1,11 @@
+# ExcelDna.Interop
+
+This package provides local copies of these Microsoft Office primary interop assemblies:
+
+- `Microsoft.Office.Interop.Excel.dll`
+- `Microsoft.Vbe.Interop.dll`
+- `office.dll`
+
+The assemblies are available for .NET Framework 4.5.2 and `net6.0-windows7.0` projects. The package configures C# and Visual Basic projects to embed the interop types and not copy the assemblies to the output directory. F# projects are excluded from that build behavior.
+
+For Excel-DNA documentation, see [excel-dna.net](https://excel-dna.net/).
diff --git a/Package/package-interop.cmd b/Package/package-interop.cmd
index a41ad1df..3f23fe1f 100644
--- a/Package/package-interop.cmd
+++ b/Package/package-interop.cmd
@@ -12,13 +12,13 @@ if not exist "%outputPath%" mkdir "%outputPath%"
echo on
-nuget.exe pack "%basePath%\Excel-DNA.Interop\Excel-DNA.Interop.nuspec" -BasePath "%basePath%\Excel-DNA.Interop" -OutputDirectory "%outputPath%" -Verbosity detailed -NonInteractive -Prop ExcelDnaVersion="%ExcelDnaVersion%"
+"%basePath%\nuget.exe" pack "%basePath%\Excel-DNA.Interop\Excel-DNA.Interop.nuspec" -BasePath "%basePath%\Excel-DNA.Interop" -OutputDirectory "%outputPath%" -Verbosity detailed -NonInteractive -Prop ExcelDnaVersion="%ExcelDnaVersion%"
@if errorlevel 1 goto end
-nuget.exe pack "%basePath%\ExcelDna.Interop\ExcelDna.Interop.nuspec" -BasePath "%basePath%\ExcelDna.Interop" -OutputDirectory "%outputPath%" -Verbosity detailed -NonInteractive
+"%basePath%\nuget.exe" pack "%basePath%\ExcelDna.Interop\ExcelDna.Interop.nuspec" -BasePath "%basePath%\ExcelDna.Interop" -OutputDirectory "%outputPath%" -Verbosity detailed -NonInteractive
@if errorlevel 1 goto end
-nuget.exe pack "%basePath%\ExcelDna.Interop.Dao\ExcelDna.Interop.Dao.nuspec" -BasePath "%basePath%\ExcelDna.Interop.Dao" -OutputDirectory "%outputPath%" -Verbosity detailed -NonInteractive
+"%basePath%\nuget.exe" pack "%basePath%\ExcelDna.Interop.Dao\ExcelDna.Interop.Dao.nuspec" -BasePath "%basePath%\ExcelDna.Interop.Dao" -OutputDirectory "%outputPath%" -Verbosity detailed -NonInteractive
@if errorlevel 1 goto end
:end
diff --git a/Package/push-interop.cmd b/Package/push-interop.cmd
index 131279a8..8816a62a 100644
--- a/Package/push-interop.cmd
+++ b/Package/push-interop.cmd
@@ -7,13 +7,13 @@ set outputPath=%basePath%\nupkg
if not exist "%outputPath%" mkdir "%outputPath%"
-nuget.exe push "%outputPath%\Excel-DNA.Interop.15.0.1.nupkg" -Source https://api.nuget.org/v3/index.json -Verbosity detailed -NonInteractive
+nuget.exe push "%outputPath%\Excel-DNA.Interop.16.0.0.nupkg" -Source https://api.nuget.org/v3/index.json -Verbosity detailed -NonInteractive
@if errorlevel 1 goto end
-nuget.exe push "%outputPath%\ExcelDna.Interop.15.0.1.nupkg" -Source https://api.nuget.org/v3/index.json -Verbosity detailed -NonInteractive
+nuget.exe push "%outputPath%\ExcelDna.Interop.16.0.0.nupkg" -Source https://api.nuget.org/v3/index.json -Verbosity detailed -NonInteractive
@if errorlevel 1 goto end
-nuget.exe push "%outputPath%\ExcelDna.Interop.Dao.15.0.1.nupkg" -Source https://api.nuget.org/v3/index.json -Verbosity detailed -NonInteractive
+nuget.exe push "%outputPath%\ExcelDna.Interop.Dao.16.0.0.nupkg" -Source https://api.nuget.org/v3/index.json -Verbosity detailed -NonInteractive
@if errorlevel 1 goto end
:end
diff --git a/Source/ExcelDna.Integration/ComInterop/ComServer.cs b/Source/ExcelDna.Integration/ComInterop/ComServer.cs
index 6f0fcfa3..0ab571a4 100644
--- a/Source/ExcelDna.Integration/ComInterop/ComServer.cs
+++ b/Source/ExcelDna.Integration/ComInterop/ComServer.cs
@@ -95,6 +95,7 @@ internal static HRESULT DllGetClassObject(CLSID clsid, IID iid, out IntPtr ppunk
ComWrappers cw = new System.Runtime.InteropServices.Marshalling.StrategyBasedComWrappers();
nint ptr = cw.GetOrCreateComInterfaceForObject(factory, CreateComInterfaceFlags.None);
HRESULT hrQI = Marshal.QueryInterface(ptr, in iid, out ppunk);
+ Marshal.Release(ptr);
#else
IntPtr punkFactory = Marshal.GetIUnknownForObject(factory);
HRESULT hrQI = Marshal.QueryInterface(punkFactory, ref iid, out ppunk);
diff --git a/Source/ExcelDna.Integration/ComInterop/DummyComAddIn.cs b/Source/ExcelDna.Integration/ComInterop/DummyComAddIn.cs
index 67451754..65e051e4 100644
--- a/Source/ExcelDna.Integration/ComInterop/DummyComAddIn.cs
+++ b/Source/ExcelDna.Integration/ComInterop/DummyComAddIn.cs
@@ -14,24 +14,29 @@ namespace ExcelDna.Integration.ComInterop
[GeneratedComClass]
internal partial class DummyComAddIn : Generator.Interfaces.IDTExtensibility2
{
+ private const int S_OK = 0;
+ private const int E_NOTIMPL = unchecked((int)0x80004001);
+
public int GetTypeInfoCount(out uint pctinfo)
{
- throw new NotImplementedException();
+ pctinfo = 0;
+ return S_OK;
}
public int GetTypeInfo(uint iTInfo, uint lcid, out nint ppTInfo)
{
- throw new NotImplementedException();
+ ppTInfo = 0;
+ return E_NOTIMPL;
}
- public int GetIDsOfNames(Guid riid, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 2)] string[] rgszNames, uint cNames, uint lcid, [In][Out][MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] int[] rgDispId)
+ public int GetIDsOfNames(in Guid riid, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 2)] string[] rgszNames, uint cNames, uint lcid, [In][Out][MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] int[] rgDispId)
{
- throw new NotImplementedException();
+ return E_NOTIMPL;
}
- public int Invoke(int dispIdMember, Guid riid, uint lcid, INVOKEKIND wFlags, [MarshalUsing(typeof(Generator.Interfaces.DispParamsMarshaller))] in Generator.Interfaces.DispParams pDispParams, nint pVarResult, nint pExcepInfo, nint puArgErr)
+ public int Invoke(int dispIdMember, in Guid riid, uint lcid, ushort wFlags, [MarshalUsing(typeof(Generator.Interfaces.DispParamsMarshaller))] in Generator.Interfaces.DispParams pDispParams, nint pVarResult, nint pExcepInfo, nint puArgErr)
{
- throw new NotImplementedException();
+ return E_NOTIMPL;
}
#region IDTExtensibility2 interface
diff --git a/Source/ExcelDna.Integration/ComInterop/Generator/ExcelObserverRtdServer.cs b/Source/ExcelDna.Integration/ComInterop/Generator/ExcelObserverRtdServer.cs
index c597f961..ee948081 100644
--- a/Source/ExcelDna.Integration/ComInterop/Generator/ExcelObserverRtdServer.cs
+++ b/Source/ExcelDna.Integration/ComInterop/Generator/ExcelObserverRtdServer.cs
@@ -12,6 +12,9 @@ namespace ExcelDna.Integration.ComInterop.Generator
[GeneratedComClass]
internal partial class ExcelObserverRtdServer : Rtd.ExcelObserverRtdServer, IRtdServer
{
+ private const int S_OK = 0;
+ private const int E_NOTIMPL = unchecked((int)0x80004001);
+
private Dispatcher dispatcher;
public ExcelObserverRtdServer()
@@ -29,22 +32,24 @@ public ExcelObserverRtdServer()
// IDispatch:
public int GetTypeInfoCount(out uint pctinfo)
{
- throw new NotImplementedException();
+ pctinfo = 0;
+ return S_OK;
}
public int GetTypeInfo(uint iTInfo, uint lcid, out nint ppTInfo)
{
- throw new NotImplementedException();
+ ppTInfo = 0;
+ return E_NOTIMPL;
}
- public int GetIDsOfNames(Guid riid, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 2)] string[] rgszNames, uint cNames, uint lcid, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2), Out] int[] rgDispId)
+ public int GetIDsOfNames(in Guid riid, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 2)] string[] rgszNames, uint cNames, uint lcid, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2), Out] int[] rgDispId)
{
dispatcher.GetIDsOfNames(rgszNames, rgDispId);
return 0;
}
- public int Invoke(int dispIdMember, Guid riid, uint lcid, INVOKEKIND wFlags, [MarshalUsing(typeof(DispParamsMarshaller))] in DispParams pDispParams, nint pVarResult, nint pExcepInfo, nint puArgErr)
+ public int Invoke(int dispIdMember, in Guid riid, uint lcid, ushort wFlags, [MarshalUsing(typeof(DispParamsMarshaller))] in DispParams pDispParams, nint pVarResult, nint pExcepInfo, nint puArgErr)
{
dispatcher.Invoke(dispIdMember, pDispParams, pVarResult);
diff --git a/Source/ExcelDna.Integration/ComInterop/Generator/ExcelRibbon.cs b/Source/ExcelDna.Integration/ComInterop/Generator/ExcelRibbon.cs
index 99486d1e..62816b35 100644
--- a/Source/ExcelDna.Integration/ComInterop/Generator/ExcelRibbon.cs
+++ b/Source/ExcelDna.Integration/ComInterop/Generator/ExcelRibbon.cs
@@ -15,6 +15,10 @@ namespace ExcelDna.Integration.ComInterop.Generator
[GeneratedComClass]
internal partial class ExcelRibbon : ExcelComAddIn, Interfaces.IDTExtensibility2, Interfaces.IRibbonExtensibility
{
+ private const int S_OK = 0;
+ private const int E_NOTIMPL = unchecked((int)0x80004001);
+ private const int DISP_E_UNKNOWNNAME = unchecked((int)0x80020006);
+
private MethodInfo[] methods;
private CustomUI.IExcelRibbon customRibbon;
@@ -26,23 +30,29 @@ public ExcelRibbon(ITypeHelper t)
public int GetTypeInfoCount(out uint pctinfo)
{
- throw new NotImplementedException();
+ pctinfo = 0;
+ return S_OK;
}
public int GetTypeInfo(uint iTInfo, uint lcid, out nint ppTInfo)
{
- throw new NotImplementedException();
+ ppTInfo = 0;
+ return E_NOTIMPL;
}
- public int GetIDsOfNames(Guid riid, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 2)] string[] rgszNames, uint cNames, uint lcid, [In][Out][MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] int[] rgDispId)
+ public int GetIDsOfNames(in Guid riid, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 2)] string[] rgszNames, uint cNames, uint lcid, [In][Out][MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] int[] rgDispId)
{
+ bool foundAll = true;
for (int i = 0; i < cNames; ++i)
+ {
rgDispId[i] = (rgszNames[i] == "LoadImage") ? methods.Length : Array.FindIndex(methods, m => m?.Name == rgszNames[i]);
+ foundAll &= rgDispId[i] >= 0;
+ }
- return 0;
+ return foundAll ? S_OK : DISP_E_UNKNOWNNAME;
}
- public int Invoke(int dispIdMember, Guid riid, uint lcid, INVOKEKIND wFlags, [MarshalUsing(typeof(Generator.Interfaces.DispParamsMarshaller))] in Generator.Interfaces.DispParams pDispParams, nint pVarResult, nint pExcepInfo, nint puArgErr)
+ public int Invoke(int dispIdMember, in Guid riid, uint lcid, ushort wFlags, [MarshalUsing(typeof(Generator.Interfaces.DispParamsMarshaller))] in Generator.Interfaces.DispParams pDispParams, nint pVarResult, nint pExcepInfo, nint puArgErr)
{
try
{
@@ -139,8 +149,17 @@ public virtual void OnBeginShutdown(ref Generator.Interfaces.SafeArray custom)
public int GetCustomUI([MarshalAs(UnmanagedType.BStr)] string RibbonID, [MarshalAs(UnmanagedType.BStr)] out string result)
{
- result = customRibbon.GetCustomUI(RibbonID);
- return 0;
+ try
+ {
+ result = customRibbon.GetCustomUI(RibbonID);
+ return S_OK;
+ }
+ catch (Exception ex)
+ {
+ ExcelDna.Logging.Logger.ComAddIn.Error(ex, "Ribbon GetCustomUI failed");
+ result = string.Empty;
+ return E_NOTIMPL;
+ }
}
#endregion
diff --git a/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/ArrayMarshaller.cs b/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/ArrayMarshaller.cs
index 3685f110..603fb15f 100644
--- a/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/ArrayMarshaller.cs
+++ b/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/ArrayMarshaller.cs
@@ -1,16 +1,30 @@
#if COM_GENERATED
+using System;
using System.Diagnostics.CodeAnalysis;
-using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace ExcelDna.Integration.ComInterop.Generator.Interfaces
{
internal static class ArrayMarshaller
{
- public unsafe static nint ArrayToPtr(T[] str)
+ public static nint ArrayToPtr(T[] values)
{
- return (nint)Unsafe.AsPointer(ref MemoryMarshal.GetArrayDataReference(str));
+ if (values == null || values.Length == 0)
+ return nint.Zero;
+
+ int size = Marshal.SizeOf();
+ nint result = Marshal.AllocHGlobal(size * values.Length);
+ for (int i = 0; i < values.Length; ++i)
+ Marshal.StructureToPtr(values[i], result + i * size, false);
+
+ return result;
+ }
+
+ public static void FreePtr(nint ptr)
+ {
+ if (ptr != nint.Zero)
+ Marshal.FreeHGlobal(ptr);
}
public static T[] PtrToArray<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T>(nint str, int len)
diff --git a/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/DispParamsMarshaller.cs b/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/DispParamsMarshaller.cs
index e0edf5ef..c1fb0134 100644
--- a/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/DispParamsMarshaller.cs
+++ b/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/DispParamsMarshaller.cs
@@ -11,11 +11,18 @@ internal static class DispParamsMarshaller
{
public static unsafe DispParamsNative ConvertToUnmanaged(DispParams managed)
{
+ int* rgdispidNamedArgs = null;
+ if (managed.rgdispidNamedArgs != 0)
+ {
+ rgdispidNamedArgs = (int*)Marshal.AllocHGlobal(sizeof(int));
+ *rgdispidNamedArgs = managed.rgdispidNamedArgs;
+ }
+
return new DispParamsNative
{
cArgs = managed.cArgs,
cNamedArgs = managed.cNamedArgs,
- rgdispidNamedArgs = managed.rgdispidNamedArgs != 0 ? &managed.rgdispidNamedArgs : null,
+ rgdispidNamedArgs = rgdispidNamedArgs,
rgvarg =
managed.rgvarg != null
? ArrayMarshaller.ArrayToPtr(managed.rgvarg.Reverse().Select(VariantMarshaller.ConvertToUnmanaged).ToArray())
@@ -39,6 +46,22 @@ public static unsafe DispParams ConvertToManaged(DispParamsNative unmanaged)
};
}
+ public static unsafe void Free(DispParamsNative unmanaged)
+ {
+ if (unmanaged.rgvarg != 0)
+ {
+ int size = Marshal.SizeOf();
+ for (int i = 0; i < unmanaged.cArgs; ++i)
+ {
+ VariantMarshaller.Free(Marshal.PtrToStructure(unmanaged.rgvarg + i * size));
+ }
+ ArrayMarshaller.FreePtr(unmanaged.rgvarg);
+ }
+
+ if (unmanaged.rgdispidNamedArgs != null)
+ Marshal.FreeHGlobal((nint)unmanaged.rgdispidNamedArgs);
+ }
+
public static void UpdateArg(DispParams dp, Variant v, int i)
{
int ri = dp.cArgs - 1 - i;
diff --git a/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/DispatchObject.cs b/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/DispatchObject.cs
index b179f863..6f67143c 100644
--- a/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/DispatchObject.cs
+++ b/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/DispatchObject.cs
@@ -106,7 +106,7 @@ private int[] GetDispIDs(string propName)
var dispIds = new int[names.Length];
var hr = dispatch!.GetIDsOfNames(
- emptyGuid,
+ in emptyGuid,
names,
(uint)names.Length,
LOCALE_USER_DEFAULT,
@@ -126,9 +126,9 @@ private int[] GetDispIDs(string propName)
var hr = dispatch!.Invoke(
dispIds[0],
- emptyGuid,
+ in emptyGuid,
LOCALE_USER_DEFAULT,
- kind,
+ (ushort)kind,
dispParams,
variantResult.Ptr,
0,
diff --git a/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/IDispatch.cs b/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/IDispatch.cs
index d176a244..806be2e4 100644
--- a/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/IDispatch.cs
+++ b/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/IDispatch.cs
@@ -19,7 +19,7 @@ internal partial interface IDispatch
[PreserveSig]
int GetIDsOfNames(
- Guid riid,
+ in Guid riid,
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 2)] string[] rgszNames,
uint cNames,
uint lcid,
@@ -29,9 +29,9 @@ int GetIDsOfNames(
[PreserveSig]
int Invoke(
int dispIdMember,
- Guid riid,
+ in Guid riid,
uint lcid,
- INVOKEKIND wFlags,
+ ushort wFlags,
[MarshalUsing(typeof(DispParamsMarshaller))] in DispParams pDispParams,
nint pVarResult,
nint pExcepInfo,
diff --git a/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/IRibbonControl.cs b/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/IRibbonControl.cs
index 9e6eb2d2..42bee2b9 100644
--- a/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/IRibbonControl.cs
+++ b/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/IRibbonControl.cs
@@ -13,7 +13,7 @@ internal partial interface IRibbonControl : IDispatch
int get_Id([MarshalAs(UnmanagedType.BStr)] out string result);
[PreserveSig]
- int get_Context(nint result);
+ int get_Context(out nint result);
[PreserveSig]
int get_Tag([MarshalAs(UnmanagedType.BStr)] out string result);
diff --git a/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/SafeArray.cs b/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/SafeArray.cs
index 16d4fe73..66d1635e 100644
--- a/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/SafeArray.cs
+++ b/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/SafeArray.cs
@@ -23,6 +23,9 @@ internal partial struct SafeArray
[System.Runtime.InteropServices.DllImport("oleaut32.dll", ExactSpelling = true)]
public static unsafe extern /*SafeArray**/nint SafeArrayCreate(ushort vt, uint cDims, /*SAFEARRAYBOUND**/nint rgsabound);
+ [System.Runtime.InteropServices.DllImport("oleaut32.dll", ExactSpelling = true)]
+ public static extern int SafeArrayDestroy(nint psa);
+
public ushort cDims;
public ushort fFeatures;
public uint cbElements;
diff --git a/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/UnknownObject.cs b/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/UnknownObject.cs
index d59dd371..d79e5206 100644
--- a/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/UnknownObject.cs
+++ b/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/UnknownObject.cs
@@ -1,6 +1,7 @@
#if COM_GENERATED
using System;
+using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
namespace ExcelDna.Integration.ComInterop.Generator.Interfaces
@@ -17,7 +18,11 @@ public UnknownObject(IntPtr unknown)
public unsafe bool HasInterface(ref Guid guid)
{
StrategyBasedComWrappers.DefaultIUnknownStrategy.QueryInterface(P.ToPointer(), in guid, out void* ppObj);
- return ppObj != null;
+ if (ppObj == null)
+ return false;
+
+ Marshal.Release((IntPtr)ppObj);
+ return true;
}
public unsafe int QueryInterface(ref Guid guid, out IntPtr ppv)
diff --git a/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/VariantMarshaller.cs b/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/VariantMarshaller.cs
index bea5d735..5139898e 100644
--- a/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/VariantMarshaller.cs
+++ b/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/VariantMarshaller.cs
@@ -111,6 +111,7 @@ private static VariantNative VariantArrayToUnmanaged(Array array)
Marshal.StructureToPtr(new SAFEARRAYBOUND { cElements = (uint)array.GetLength(1), lLbound = 0 }, pBounds + Marshal.SizeOf(), false);
nint psa = SafeArray.SafeArrayCreate((ushort)VariantTypeNative.VT_VARIANT, (uint)array.Rank, pBounds);
+ Marshal.FreeHGlobal(pBounds);
SafeArray sa = Marshal.PtrToStructure(psa);
for (int col = 0; col < array.GetLength(1); ++col)
@@ -146,6 +147,21 @@ public static void UpdateRefBool(VariantNative unmanaged, bool v)
short boolVal = v ? (short)VariantBoolNative.VARIANT_TRUE : (short)VariantBoolNative.VARIANT_FALSE;
Marshal.StructureToPtr(boolVal, unmanaged.pboolVal, false);
}
+
+ public static void Free(VariantNative unmanaged)
+ {
+ switch ((VariantTypeNative)unmanaged.vt)
+ {
+ case VariantTypeNative.VT_BSTR:
+ if (unmanaged.bstrVal != 0)
+ Marshal.FreeBSTR(unmanaged.bstrVal);
+ break;
+ case VT_VARIANT_ARRAY:
+ if (unmanaged.parray != 0)
+ SafeArray.SafeArrayDestroy(unmanaged.parray);
+ break;
+ }
+ }
}
}
diff --git a/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/VariantResultMarshaller.cs b/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/VariantResultMarshaller.cs
index c86ee340..3dc44360 100644
--- a/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/VariantResultMarshaller.cs
+++ b/Source/ExcelDna.Integration/ComInterop/Generator/Interfaces/VariantResultMarshaller.cs
@@ -14,6 +14,7 @@ internal class VariantResultMarshaller : IDisposable
public VariantResultMarshaller()
{
Ptr = Marshal.AllocHGlobal(Marshal.SizeOf());
+ Marshal.StructureToPtr(default(VariantNative), Ptr, false);
}
public Variant GetResult()
@@ -26,6 +27,7 @@ protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
+ VariantMarshaller.Free(Marshal.PtrToStructure(Ptr));
Marshal.FreeHGlobal(Ptr);
disposedValue = true;
}
diff --git a/Source/ExcelDna.Integration/ComInterop/Generator/RTDUpdateEvent.cs b/Source/ExcelDna.Integration/ComInterop/Generator/RTDUpdateEvent.cs
index 47193892..2ab5deee 100644
--- a/Source/ExcelDna.Integration/ComInterop/Generator/RTDUpdateEvent.cs
+++ b/Source/ExcelDna.Integration/ComInterop/Generator/RTDUpdateEvent.cs
@@ -10,6 +10,9 @@ namespace ExcelDna.Integration.ComInterop.Generator
[GeneratedComClass]
internal partial class RTDUpdateEvent : Rtd.IRTDUpdateEvent, IRTDUpdateEvent
{
+ private const int S_OK = 0;
+ private const int E_NOTIMPL = unchecked((int)0x80004001);
+
private IRTDUpdateEvent impl;
public RTDUpdateEvent(IRTDUpdateEvent impl)
@@ -61,22 +64,24 @@ void IRTDUpdateEvent.Disconnect()
int IDispatch.GetTypeInfoCount(out uint pctinfo)
{
- throw new NotImplementedException();
+ pctinfo = 0;
+ return S_OK;
}
int IDispatch.GetTypeInfo(uint iTInfo, uint lcid, out nint ppTInfo)
{
- throw new NotImplementedException();
+ ppTInfo = 0;
+ return E_NOTIMPL;
}
- int IDispatch.GetIDsOfNames(Guid riid, string[] rgszNames, uint cNames, uint lcid, int[] rgDispId)
+ int IDispatch.GetIDsOfNames(in Guid riid, string[] rgszNames, uint cNames, uint lcid, int[] rgDispId)
{
- throw new NotImplementedException();
+ return E_NOTIMPL;
}
- int IDispatch.Invoke(int dispIdMember, Guid riid, uint lcid, INVOKEKIND wFlags, in DispParams pDispParams, nint pVarResult, nint pExcepInfo, nint puArgErr)
+ int IDispatch.Invoke(int dispIdMember, in Guid riid, uint lcid, ushort wFlags, in DispParams pDispParams, nint pVarResult, nint pExcepInfo, nint puArgErr)
{
- throw new NotImplementedException();
+ return E_NOTIMPL;
}
}
}
diff --git a/Source/ExcelDna.Integration/ComInterop/Util.cs b/Source/ExcelDna.Integration/ComInterop/Util.cs
index 3f79d715..fdc05bc4 100644
--- a/Source/ExcelDna.Integration/ComInterop/Util.cs
+++ b/Source/ExcelDna.Integration/ComInterop/Util.cs
@@ -30,12 +30,20 @@ public static IType TypeAdapter
public static int QueryInterfaceForObject(object o, Guid guid, out IntPtr ppv)
{
Guid iid = guid;
+ IntPtr pUnk = GetIUnknownForObject(o);
- return Marshal.QueryInterface(GetIUnknownForObject(o),
+ try
+ {
+ return Marshal.QueryInterface(pUnk,
#if !COM_GENERATED
- ref
+ ref
#endif
- iid, out ppv);
+ iid, out ppv);
+ }
+ finally
+ {
+ Marshal.Release(pUnk);
+ }
}
private static IntPtr GetIUnknownForObject(object o)
diff --git a/Source/ExcelDna.Integration/CustomUI/RibbonControl.cs b/Source/ExcelDna.Integration/CustomUI/RibbonControl.cs
index 2c6ba367..f5b77224 100644
--- a/Source/ExcelDna.Integration/CustomUI/RibbonControl.cs
+++ b/Source/ExcelDna.Integration/CustomUI/RibbonControl.cs
@@ -1,4 +1,6 @@
-#if COM_GENERATED
+#if COM_GENERATED
+
+using System.Runtime.InteropServices;
namespace ExcelDna.Integration.CustomUI
{
@@ -24,6 +26,19 @@ public string Tag
}
}
+ public object Context
+ {
+ get
+ {
+ int hr = control.get_Context(out nint result);
+ Marshal.ThrowExceptionForHR(hr);
+ if (result == 0)
+ return null;
+
+ return new ComInterop.Generator.DynamicComObject(new ComInterop.Generator.Interfaces.DispatchObject(result));
+ }
+ }
+
internal RibbonControl(ComInterop.Generator.Interfaces.IRibbonControl control)
{
this.control = control;
diff --git a/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs b/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs
index 29c2fe50..40c94868 100644
--- a/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs
+++ b/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs
@@ -78,7 +78,7 @@ public static short Initialize(void* xlAddInExportInfoAddress, void* hModuleXll,
{
if (actions.Length > 0)
actions += ",\r\n";
- actions += $"typeof({Util.GetFullTypeName(m.ContainingType)}).GetMethod(\"{m.Name}\")!";
+ actions += GetMethod(m);
}
addIns += $"{regHost}.ExcelAddIns.Add(new ExcelDna.Integration.TypeHelper<{Util.GetFullTypeName(i.Type)}>([{actions}]));\r\n";
@@ -221,7 +221,18 @@ public void Initialize(GeneratorInitializationContext context)
private static string GetMethod(IMethodSymbol method)
{
- return $"typeof({Util.GetFullTypeName(method.ContainingType)}).GetMethod(\"{method.Name}\")!";
+ return $"typeof({Util.GetFullTypeName(method.ContainingType)}).GetMethod(\"{method.Name}\", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance, null, new Type[] {{ {GetParameterTypes(method)} }}, null)!";
+ }
+
+ private static string GetParameterTypes(IMethodSymbol method)
+ {
+ return string.Join(", ", method.Parameters.Select(GetParameterType));
+ }
+
+ private static string GetParameterType(IParameterSymbol parameter)
+ {
+ string type = $"typeof({Util.GetFullTypeOfTypeName(parameter.Type)})";
+ return parameter.RefKind == RefKind.None ? type : $"{type}.MakeByRefType()";
}
private static string GetTypeRefs(string methodType, string extendedMethodType, int parameterCount)
diff --git a/Source/ExcelDna.SourceGenerator.NativeAOT/Util.cs b/Source/ExcelDna.SourceGenerator.NativeAOT/Util.cs
index 96197e63..f41bd362 100644
--- a/Source/ExcelDna.SourceGenerator.NativeAOT/Util.cs
+++ b/Source/ExcelDna.SourceGenerator.NativeAOT/Util.cs
@@ -11,6 +11,11 @@ public static string GetFullTypeName(ITypeSymbol type)
return type.ToDisplayString().Replace("[*,*]", "[,]");
}
+ public static string GetFullTypeOfTypeName(ITypeSymbol type)
+ {
+ return type.ToDisplayString(FullTypeOfTypeNameFormat).Replace("[*,*]", "[,]");
+ }
+
public static string GetFullGenericTypeName(INamedTypeSymbol type)
{
return type.ToDisplayString(FullGenericNameFormat);
@@ -342,5 +347,9 @@ static bool IsString2DArray(ITypeSymbol type)
private static SymbolDisplayFormat FullNameFormat = new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces);
private static SymbolDisplayFormat FullGenericNameFormat = new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, genericsOptions: SymbolDisplayGenericsOptions.None);
+ private static SymbolDisplayFormat FullTypeOfTypeNameFormat = new SymbolDisplayFormat(
+ typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
+ genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters,
+ miscellaneousOptions: SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers | SymbolDisplayMiscellaneousOptions.UseSpecialTypes);
}
}
diff --git a/Source/ExcelDna.TestAOT/ExcelDna.TestAOT.csproj b/Source/ExcelDna.TestAOT/ExcelDna.TestAOT.csproj
index 563c64f8..7058ea00 100644
--- a/Source/ExcelDna.TestAOT/ExcelDna.TestAOT.csproj
+++ b/Source/ExcelDna.TestAOT/ExcelDna.TestAOT.csproj
@@ -8,23 +8,29 @@
true
- win-x64
+ win-x64
true
true
- ExcelDna.TestAOT64
enable
enable
true
+
+ x86
+ x64
+ 64
+ ExcelDna.TestAOT$(ExcelDnaNativeAOTBitnessSuffix)
+ $(MSBuildProjectDirectory)\..\ExcelDna.Host.NativeAOT\bin\$(Configuration)\$(ExcelDnaNativeAOTPlatform)\ExcelDna.Host.NativeAOT.$(ExcelDnaNativeAOTPlatform).xll
+
true
-
+
@@ -39,8 +45,12 @@
-
-
+
+
+
diff --git a/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/ExcelDna.AddIn.RuntimeTestsAOT.csproj b/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/ExcelDna.AddIn.RuntimeTestsAOT.csproj
index 5fb026ef..26368308 100644
--- a/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/ExcelDna.AddIn.RuntimeTestsAOT.csproj
+++ b/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/ExcelDna.AddIn.RuntimeTestsAOT.csproj
@@ -8,31 +8,41 @@
true
- win-x64
+ win-x64
true
true
- ExcelDna.AddIn.RuntimeTestsAOT64
enable
enable
true
+
+ x86
+ x64
+ 64
+ ExcelDna.AddIn.RuntimeTestsAOT$(ExcelDnaNativeAOTBitnessSuffix)
+ $(MSBuildProjectDirectory)\..\..\ExcelDna.Host.NativeAOT\bin\$(Configuration)\$(ExcelDnaNativeAOTPlatform)\ExcelDna.Host.NativeAOT.$(ExcelDnaNativeAOTPlatform).xll
+
true
-
+
-
-
+
+
+
diff --git a/Source/Tests/ExcelDna.SourceGenerator.NativeAOT.Tests/Generator.cs b/Source/Tests/ExcelDna.SourceGenerator.NativeAOT.Tests/Generator.cs
index 5abeb2cf..907d8d6b 100644
--- a/Source/Tests/ExcelDna.SourceGenerator.NativeAOT.Tests/Generator.cs
+++ b/Source/Tests/ExcelDna.SourceGenerator.NativeAOT.Tests/Generator.cs
@@ -27,7 +27,7 @@ public static string NativeParamsJoinString(string separator, params string[] va
}
""", functions: """
List typeRefs = new List();
- ExcelDna.Registration.StaticRegistration.MethodsForRegistration.Add(typeof(ExcelDna.AddIn.RuntimeTestsAOT.Functions).GetMethod("NativeParamsJoinString")!);
+ ExcelDna.Registration.StaticRegistration.MethodsForRegistration.Add(typeof(ExcelDna.AddIn.RuntimeTestsAOT.Functions).GetMethod("NativeParamsJoinString", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance, null, new Type[] { typeof(string), typeof(string[]) }, null)!);
typeRefs.Add(typeof(Func));
typeRefs.Add(typeof(System.Linq.Expressions.Expression>));
typeRefs.Add(typeof(ExcelDna.Integration.ExtendedFunc2));
@@ -68,7 +68,7 @@ public static string NativeOptional(object refRange, double targetValue, int max
}
""", functions: """
List typeRefs = new List();
- ExcelDna.Registration.StaticRegistration.MethodsForRegistration.Add(typeof(ExcelDna.AddIn.RuntimeTestsAOT.Functions).GetMethod("NativeOptional")!);
+ ExcelDna.Registration.StaticRegistration.MethodsForRegistration.Add(typeof(ExcelDna.AddIn.RuntimeTestsAOT.Functions).GetMethod("NativeOptional", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance, null, new Type[] { typeof(object), typeof(double), typeof(int), typeof(bool) }, null)!);
typeRefs.Add(typeof(Func