From be083e12a7aa7c427e2e6c5923ce58617d485a80 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sun, 19 Jan 2025 10:21:04 +0500 Subject: [PATCH 01/60] Created ExcelDna.Host.Shared project and moved common files from ExcelDna.Host to it. --- .../ExcelDna.Host.Shared.vcxitems | 45 ++++++++++++ .../ExcelDna.Host.rc | 0 .../LPenHelper.cpp | 0 .../LPenHelper.h | 0 .../TempDir.cpp | 0 .../TempDir.h | 0 .../addin.cpp | 0 .../dnainfo.cpp | 0 .../dnainfo.h | 0 .../exports.def | 0 .../exports.h | 0 .../exports32.cpp | 0 .../exports64.asm | 0 .../host.h | 0 .../loader.cpp | 0 .../loader.h | 0 .../main.cpp | 0 .../resource.h | 0 .../utils.cpp | 0 .../utils.h | 0 Source/ExcelDna.Host/ExcelDna.Host.vcxproj | 37 ++-------- .../ExcelDna.Host.vcxproj.filters | 68 ------------------- Source/ExcelDna.sln | 4 ++ 23 files changed, 54 insertions(+), 100 deletions(-) create mode 100644 Source/ExcelDna.Host.Shared/ExcelDna.Host.Shared.vcxitems rename Source/{ExcelDna.Host => ExcelDna.Host.Shared}/ExcelDna.Host.rc (100%) rename Source/{ExcelDna.Host => ExcelDna.Host.Shared}/LPenHelper.cpp (100%) rename Source/{ExcelDna.Host => ExcelDna.Host.Shared}/LPenHelper.h (100%) rename Source/{ExcelDna.Host => ExcelDna.Host.Shared}/TempDir.cpp (100%) rename Source/{ExcelDna.Host => ExcelDna.Host.Shared}/TempDir.h (100%) rename Source/{ExcelDna.Host => ExcelDna.Host.Shared}/addin.cpp (100%) rename Source/{ExcelDna.Host => ExcelDna.Host.Shared}/dnainfo.cpp (100%) rename Source/{ExcelDna.Host => ExcelDna.Host.Shared}/dnainfo.h (100%) rename Source/{ExcelDna.Host => ExcelDna.Host.Shared}/exports.def (100%) rename Source/{ExcelDna.Host => ExcelDna.Host.Shared}/exports.h (100%) rename Source/{ExcelDna.Host => ExcelDna.Host.Shared}/exports32.cpp (100%) rename Source/{ExcelDna.Host => ExcelDna.Host.Shared}/exports64.asm (100%) rename Source/{ExcelDna.Host => ExcelDna.Host.Shared}/host.h (100%) rename Source/{ExcelDna.Host => ExcelDna.Host.Shared}/loader.cpp (100%) rename Source/{ExcelDna.Host => ExcelDna.Host.Shared}/loader.h (100%) rename Source/{ExcelDna.Host => ExcelDna.Host.Shared}/main.cpp (100%) rename Source/{ExcelDna.Host => ExcelDna.Host.Shared}/resource.h (100%) rename Source/{ExcelDna.Host => ExcelDna.Host.Shared}/utils.cpp (100%) rename Source/{ExcelDna.Host => ExcelDna.Host.Shared}/utils.h (100%) diff --git a/Source/ExcelDna.Host.Shared/ExcelDna.Host.Shared.vcxitems b/Source/ExcelDna.Host.Shared/ExcelDna.Host.Shared.vcxitems new file mode 100644 index 00000000..16643773 --- /dev/null +++ b/Source/ExcelDna.Host.Shared/ExcelDna.Host.Shared.vcxitems @@ -0,0 +1,45 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + {65ccad73-fe1a-47f7-b8ac-3603919c49fe} + + + + %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/ExcelDna.Host/ExcelDna.Host.rc b/Source/ExcelDna.Host.Shared/ExcelDna.Host.rc similarity index 100% rename from Source/ExcelDna.Host/ExcelDna.Host.rc rename to Source/ExcelDna.Host.Shared/ExcelDna.Host.rc diff --git a/Source/ExcelDna.Host/LPenHelper.cpp b/Source/ExcelDna.Host.Shared/LPenHelper.cpp similarity index 100% rename from Source/ExcelDna.Host/LPenHelper.cpp rename to Source/ExcelDna.Host.Shared/LPenHelper.cpp diff --git a/Source/ExcelDna.Host/LPenHelper.h b/Source/ExcelDna.Host.Shared/LPenHelper.h similarity index 100% rename from Source/ExcelDna.Host/LPenHelper.h rename to Source/ExcelDna.Host.Shared/LPenHelper.h diff --git a/Source/ExcelDna.Host/TempDir.cpp b/Source/ExcelDna.Host.Shared/TempDir.cpp similarity index 100% rename from Source/ExcelDna.Host/TempDir.cpp rename to Source/ExcelDna.Host.Shared/TempDir.cpp diff --git a/Source/ExcelDna.Host/TempDir.h b/Source/ExcelDna.Host.Shared/TempDir.h similarity index 100% rename from Source/ExcelDna.Host/TempDir.h rename to Source/ExcelDna.Host.Shared/TempDir.h diff --git a/Source/ExcelDna.Host/addin.cpp b/Source/ExcelDna.Host.Shared/addin.cpp similarity index 100% rename from Source/ExcelDna.Host/addin.cpp rename to Source/ExcelDna.Host.Shared/addin.cpp diff --git a/Source/ExcelDna.Host/dnainfo.cpp b/Source/ExcelDna.Host.Shared/dnainfo.cpp similarity index 100% rename from Source/ExcelDna.Host/dnainfo.cpp rename to Source/ExcelDna.Host.Shared/dnainfo.cpp diff --git a/Source/ExcelDna.Host/dnainfo.h b/Source/ExcelDna.Host.Shared/dnainfo.h similarity index 100% rename from Source/ExcelDna.Host/dnainfo.h rename to Source/ExcelDna.Host.Shared/dnainfo.h diff --git a/Source/ExcelDna.Host/exports.def b/Source/ExcelDna.Host.Shared/exports.def similarity index 100% rename from Source/ExcelDna.Host/exports.def rename to Source/ExcelDna.Host.Shared/exports.def diff --git a/Source/ExcelDna.Host/exports.h b/Source/ExcelDna.Host.Shared/exports.h similarity index 100% rename from Source/ExcelDna.Host/exports.h rename to Source/ExcelDna.Host.Shared/exports.h diff --git a/Source/ExcelDna.Host/exports32.cpp b/Source/ExcelDna.Host.Shared/exports32.cpp similarity index 100% rename from Source/ExcelDna.Host/exports32.cpp rename to Source/ExcelDna.Host.Shared/exports32.cpp diff --git a/Source/ExcelDna.Host/exports64.asm b/Source/ExcelDna.Host.Shared/exports64.asm similarity index 100% rename from Source/ExcelDna.Host/exports64.asm rename to Source/ExcelDna.Host.Shared/exports64.asm diff --git a/Source/ExcelDna.Host/host.h b/Source/ExcelDna.Host.Shared/host.h similarity index 100% rename from Source/ExcelDna.Host/host.h rename to Source/ExcelDna.Host.Shared/host.h diff --git a/Source/ExcelDna.Host/loader.cpp b/Source/ExcelDna.Host.Shared/loader.cpp similarity index 100% rename from Source/ExcelDna.Host/loader.cpp rename to Source/ExcelDna.Host.Shared/loader.cpp diff --git a/Source/ExcelDna.Host/loader.h b/Source/ExcelDna.Host.Shared/loader.h similarity index 100% rename from Source/ExcelDna.Host/loader.h rename to Source/ExcelDna.Host.Shared/loader.h diff --git a/Source/ExcelDna.Host/main.cpp b/Source/ExcelDna.Host.Shared/main.cpp similarity index 100% rename from Source/ExcelDna.Host/main.cpp rename to Source/ExcelDna.Host.Shared/main.cpp diff --git a/Source/ExcelDna.Host/resource.h b/Source/ExcelDna.Host.Shared/resource.h similarity index 100% rename from Source/ExcelDna.Host/resource.h rename to Source/ExcelDna.Host.Shared/resource.h diff --git a/Source/ExcelDna.Host/utils.cpp b/Source/ExcelDna.Host.Shared/utils.cpp similarity index 100% rename from Source/ExcelDna.Host/utils.cpp rename to Source/ExcelDna.Host.Shared/utils.cpp diff --git a/Source/ExcelDna.Host/utils.h b/Source/ExcelDna.Host.Shared/utils.h similarity index 100% rename from Source/ExcelDna.Host/utils.h rename to Source/ExcelDna.Host.Shared/utils.h diff --git a/Source/ExcelDna.Host/ExcelDna.Host.vcxproj b/Source/ExcelDna.Host/ExcelDna.Host.vcxproj index dfb0bdfd..99c967ee 100644 --- a/Source/ExcelDna.Host/ExcelDna.Host.vcxproj +++ b/Source/ExcelDna.Host/ExcelDna.Host.vcxproj @@ -61,6 +61,7 @@ + @@ -121,7 +122,7 @@ /IGNORE:4099 - exports.def + ..\ExcelDna.Host.Shared\exports.def $(OutDir)$(TargetName).xll @@ -151,7 +152,7 @@ /IGNORE:4099 - exports.def + ..\ExcelDna.Host.Shared\exports.def $(OutDir)$(TargetName).xll @@ -177,7 +178,7 @@ /IGNORE:4099 - exports.def + ..\ExcelDna.Host.Shared\exports.def $(OutDir)$(TargetName).xll @@ -207,7 +208,7 @@ /IGNORE:4099 - exports.def + ..\ExcelDna.Host.Shared\exports.def $(OutDir)$(TargetName).xll @@ -241,35 +242,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Source/ExcelDna.Host/ExcelDna.Host.vcxproj.filters b/Source/ExcelDna.Host/ExcelDna.Host.vcxproj.filters index aa75a678..3a51a9cf 100644 --- a/Source/ExcelDna.Host/ExcelDna.Host.vcxproj.filters +++ b/Source/ExcelDna.Host/ExcelDna.Host.vcxproj.filters @@ -15,79 +15,11 @@ - - Source Files - - - Source Files - Source Files - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Source Files - - - Resource Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - - - Source Files - - \ No newline at end of file diff --git a/Source/ExcelDna.sln b/Source/ExcelDna.sln index 22c0cc28..3d772844 100644 --- a/Source/ExcelDna.sln +++ b/Source/ExcelDna.sln @@ -131,6 +131,8 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "ExcelDna.AddIn.Registration EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExcelDna.RegistrationTests", "Tests\ExcelDna.RegistrationTests\ExcelDna.RegistrationTests.csproj", "{151AE960-6320-402D-BDD0-D76DF96F2BD7}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExcelDna.Host.Shared", "ExcelDna.Host.Shared\ExcelDna.Host.Shared.vcxitems", "{65CCAD73-FE1A-47F7-B8AC-3603919C49FE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -303,7 +305,9 @@ Global EndGlobalSection GlobalSection(SharedMSBuildProjectFiles) = preSolution ExcelDna.PackedResources\ExcelDna.PackedResources.projitems*{28d046d4-b414-4daf-818f-897a97b921df}*SharedItemsImports = 5 + ExcelDna.Host.Shared\ExcelDna.Host.Shared.vcxitems*{65ccad73-fe1a-47f7-b8ac-3603919c49fe}*SharedItemsImports = 9 ExcelDna.PackedResources\ExcelDna.PackedResources.projitems*{7ebb8fa9-a153-422e-b454-144c3fb03450}*SharedItemsImports = 13 + ExcelDna.Host.Shared\ExcelDna.Host.Shared.vcxitems*{a9887347-3e93-4e4e-96df-227648e57b60}*SharedItemsImports = 4 ExcelDna.PackedResources\ExcelDna.PackedResources.projitems*{b5cc04d3-0507-4431-9f45-7c60bac3047a}*SharedItemsImports = 5 ExcelDna.PackedResources\ExcelDna.PackedResources.projitems*{dc10cec8-c6ce-4148-838f-c3dd4ea2a2a3}*SharedItemsImports = 5 ExcelDna.PackedResources\ExcelDna.PackedResources.projitems*{fd7f2ee3-9922-4825-96a2-be2c877baeb9}*SharedItemsImports = 5 From ccda90db706adf6c9856f0af78d0016ffc49f3b2 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sun, 19 Jan 2025 11:23:27 +0500 Subject: [PATCH 02/60] Created ExcelDna.Host.NativeAOT project. --- .../ExcelDna.Host.NativeAOT.vcxproj | 242 ++++++++++++++++++ .../ExcelDna.Host.NativeAOT.vcxproj.filters | 22 ++ Source/ExcelDna.Host.NativeAOT/host.cpp | 53 ++++ Source/ExcelDna.Host.Shared/host.h | 2 +- Source/ExcelDna.Host.Shared/loader.cpp | 2 +- Source/ExcelDna.Host.Shared/utils.cpp | 42 +++ Source/ExcelDna.Host.Shared/utils.h | 2 + Source/ExcelDna.Host/host.cpp | 47 +--- Source/ExcelDna.sln | 11 + 9 files changed, 377 insertions(+), 46 deletions(-) create mode 100644 Source/ExcelDna.Host.NativeAOT/ExcelDna.Host.NativeAOT.vcxproj create mode 100644 Source/ExcelDna.Host.NativeAOT/ExcelDna.Host.NativeAOT.vcxproj.filters create mode 100644 Source/ExcelDna.Host.NativeAOT/host.cpp diff --git a/Source/ExcelDna.Host.NativeAOT/ExcelDna.Host.NativeAOT.vcxproj b/Source/ExcelDna.Host.NativeAOT/ExcelDna.Host.NativeAOT.vcxproj new file mode 100644 index 00000000..a91cdf2f --- /dev/null +++ b/Source/ExcelDna.Host.NativeAOT/ExcelDna.Host.NativeAOT.vcxproj @@ -0,0 +1,242 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + MSB8012 + + + 16.0 + Win32Proj + {D50C3A8E-46F1-F61B-C8F5-ECDA05995EEB} + ExcelDnaHostNativeAOT + 10.0 + net5.0-windows + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + false + $(ProjectDir)bin\$(Configuration)\$(PlatformTarget)\ + $(ProjectDir)obj\$(Configuration)\$(PlatformTarget)\ + $(ProjectName).$(PlatformTarget) + + + false + $(ProjectDir)bin\$(Configuration)\$(PlatformTarget)\ + $(ProjectDir)obj\$(Configuration)\$(PlatformTarget)\ + $(ProjectName).$(PlatformTarget) + + + false + $(ProjectDir)bin\$(Configuration)\$(PlatformTarget)\ + $(ProjectDir)obj\$(Configuration)\$(PlatformTarget)\ + $(ProjectName).$(PlatformTarget) + + + false + $(ProjectDir)bin\$(Configuration)\$(PlatformTarget)\ + $(ProjectDir)obj\$(Configuration)\$(PlatformTarget)\ + $(ProjectName).$(PlatformTarget) + + + + Level3 + true + WIN32;EXCELDNAHOST_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + NotUsing + $(ProjectDir)Include;%(AdditionalIncludeDirectories) + MultiThreaded + ProgramDatabase + false + false + + + Windows + true + false + advapi32.lib;%(AdditionalDependencies) + false + + + /IGNORE:4099 + ..\ExcelDna.Host.Shared\exports.def + $(OutDir)$(TargetName).xll + + + + + Level3 + true + true + true + WIN32;EXCELDNAHOST_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + NotUsing + %(AdditionalIncludeDirectories) + MultiThreaded + false + false + None + + + Windows + true + true + false + false + advapi32.lib;%(AdditionalDependencies) + false + + + /IGNORE:4099 + ..\ExcelDna.Host.Shared\exports.def + $(OutDir)$(TargetName).xll + + + + + Level3 + true + EXCELDNAHOST_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + NotUsing + %(AdditionalIncludeDirectories) + MultiThreaded + ProgramDatabase + false + false + + + Windows + true + false + advapi32.lib;%(AdditionalDependencies) + false + + + /IGNORE:4099 + ..\ExcelDna.Host.Shared\exports.def + $(OutDir)$(TargetName).xll + + + + + Level3 + true + true + true + EXCELDNAHOST_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + NotUsing + %(AdditionalIncludeDirectories) + MultiThreaded + false + false + None + + + Windows + true + true + false + false + advapi32.lib;%(AdditionalDependencies) + false + + + /IGNORE:4099 + ..\ExcelDna.Host.Shared\exports.def + $(OutDir)$(TargetName).xll + + + + + stdcpp20 + Async + + + stdcpp20 + Async + Disabled + + + stdcpp20 + Async + + + stdcpp20 + Async + Disabled + + + + + + + + + + \ No newline at end of file diff --git a/Source/ExcelDna.Host.NativeAOT/ExcelDna.Host.NativeAOT.vcxproj.filters b/Source/ExcelDna.Host.NativeAOT/ExcelDna.Host.NativeAOT.vcxproj.filters new file mode 100644 index 00000000..9ca6c2a4 --- /dev/null +++ b/Source/ExcelDna.Host.NativeAOT/ExcelDna.Host.NativeAOT.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/Source/ExcelDna.Host.NativeAOT/host.cpp b/Source/ExcelDna.Host.NativeAOT/host.cpp new file mode 100644 index 00000000..a6ecbfd7 --- /dev/null +++ b/Source/ExcelDna.Host.NativeAOT/host.cpp @@ -0,0 +1,53 @@ +// Copyright (c) Govert van Drimmelen. All rights reserved. + +#include "host.h" +#include "exports.h" +#include "TempDir.h" +#include "utils.h" +#include "dnainfo.h" + +#include + +TempDir tempDir(L"ExcelDna.Host.NativeAOT"); + +int load_and_run(const std::wstring& basePath, XlAddInExportInfo* pExportInfo, HMODULE hModuleXll, LPCWSTR pathXll) +{ + std::wstring hostFile(GetAddInFullPath()); + RenameExtension(hostFile, L".dll"); + + if (!std::filesystem::exists(hostFile)) + { + std::wstring hostFileName = hostFile; + StripPath(hostFileName); + + hostFile = PathCombine(tempDir.GetPath(), hostFileName); + if (!std::filesystem::exists(hostFile)) + { + int r = WriteResourceToFile(hModuleXll, L"__MAIN__", L"NATIVE_ASSEMBLY", hostFile); + if (r != EXIT_SUCCESS) + return r; + } + } + + HINSTANCE handle = LoadLibrary(hostFile.c_str()); + + if (handle == NULL) + { + ShowHostError(L"Loading " + hostFile + L" library failed."); + return EXIT_FAILURE; + } + + typedef short(__stdcall* xladdin_initialize_native_fn)(void* xlAddInExportInfo, void* hModuleXLL, void* pPathXLL, BYTE disableAssemblyContextUnload, void* pTempDirPath); + + xladdin_initialize_native_fn init = (xladdin_initialize_native_fn)GetProcAddress(handle, "Initialize"); + if (init == NULL) + { + ShowHostError(L"GetProcAddress Initialize failed."); + return EXIT_FAILURE; + } + + std::wstring tempDirPath = tempDir.GetPath(); + short res = init(pExportInfo, hModuleXll, (void*)pathXll, false, (void*)tempDirPath.c_str()); + + return res == 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/Source/ExcelDna.Host.Shared/host.h b/Source/ExcelDna.Host.Shared/host.h index a0e089b2..ff14dfe9 100644 --- a/Source/ExcelDna.Host.Shared/host.h +++ b/Source/ExcelDna.Host.Shared/host.h @@ -4,4 +4,4 @@ #include "exports.h" -int load_runtime_and_run(const std::wstring& basePath, XlAddInExportInfo* pExportInfo, HMODULE hModuleXll, LPCWSTR pathXll); +int load_and_run(const std::wstring& basePath, XlAddInExportInfo* pExportInfo, HMODULE hModuleXll, LPCWSTR pathXll); diff --git a/Source/ExcelDna.Host.Shared/loader.cpp b/Source/ExcelDna.Host.Shared/loader.cpp index 8479244c..4a2dcf67 100644 --- a/Source/ExcelDna.Host.Shared/loader.cpp +++ b/Source/ExcelDna.Host.Shared/loader.cpp @@ -59,7 +59,7 @@ bool XlLibraryInitialize(XlAddInExportInfo* pExportInfo) WCHAR basePath[MAX_PATH] = { 0 }; WCHAR drive[_MAX_DRIVE] = { 0 }; _wsplitpath_s(xllPath.c_str(), drive, _MAX_DRIVE, basePath, MAX_PATH, NULL, 0, NULL, 0); - int result = load_runtime_and_run(std::wstring(drive) + basePath, pExportInfo, hModuleCurrent, xllPath.c_str()); + int result = load_and_run(std::wstring(drive) + basePath, pExportInfo, hModuleCurrent, xllPath.c_str()); return result == EXIT_SUCCESS; // diff --git a/Source/ExcelDna.Host.Shared/utils.cpp b/Source/ExcelDna.Host.Shared/utils.cpp index 9b9650b0..9b6d466b 100644 --- a/Source/ExcelDna.Host.Shared/utils.cpp +++ b/Source/ExcelDna.Host.Shared/utils.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include "dnainfo.h" extern HMODULE hModuleCurrent; @@ -415,3 +417,43 @@ BOOL IsBufferUTF8(BYTE* buffer, DWORD bufferLength) // Might be ANSI or some other code page. Treated as UTF-8 here. return true; } + +int WriteResourceToFile(HMODULE hModuleXll, const std::wstring& resourceName, const std::wstring& resourceType, const std::wstring& filePath) +{ + HRSRC hResManagedHost = FindResource(hModuleXll, resourceName.c_str(), resourceType.c_str()); + if (hResManagedHost == NULL) + { + ShowHostError(L"Failure to find resource " + resourceName); + return EXIT_FAILURE; + } + + HGLOBAL hManagedHost = LoadResource(hModuleXll, hResManagedHost); + if (hManagedHost == NULL) + { + ShowHostError(L"Failure to load resource " + resourceName); + return EXIT_FAILURE; + } + + void* buf = LockResource(hManagedHost); + if (buf == NULL) + { + ShowHostError(L"Failure to lock resource " + resourceName); + return EXIT_FAILURE; + } + + DWORD resSize = SizeofResource(hModuleXll, hResManagedHost); + SafeByteArray safeBytes(buf, resSize); + byte* pData; + int nSize = safeBytes.AccessData(&pData); + + HRESULT hr = WriteAllBytes(filePath, pData, nSize); + if (FAILED(hr)) + { + std::wstringstream stream; + stream << L"Saving " << resourceName << L" failed: " << std::hex << std::showbase << hr; + ShowHostError(stream.str()); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/Source/ExcelDna.Host.Shared/utils.h b/Source/ExcelDna.Host.Shared/utils.h index b38801ee..ab458c3b 100644 --- a/Source/ExcelDna.Host.Shared/utils.h +++ b/Source/ExcelDna.Host.Shared/utils.h @@ -94,3 +94,5 @@ void ShowHostError(const std::wstring& msg); std::wstring GetAddInFullPath(); BOOL IsBufferUTF8(BYTE* buffer, DWORD bufferLength); + +int WriteResourceToFile(HMODULE hModuleXll, const std::wstring& resourceName, const std::wstring& resourceType, const std::wstring& filePath); diff --git a/Source/ExcelDna.Host/host.cpp b/Source/ExcelDna.Host/host.cpp index 01b4a155..3bdb6ae2 100644 --- a/Source/ExcelDna.Host/host.cpp +++ b/Source/ExcelDna.Host/host.cpp @@ -38,7 +38,6 @@ hostfxr_close_fn close_fptr; // Forward declarations bool load_hostfxr(int& rc, std::wstring& loadError); -int write_resource_to_file(HMODULE hModuleXll, const std::wstring& resourceName, const std::wstring& resourceType, const std::wstring& filePath); load_assembly_and_get_function_pointer_fn get_dotnet_load_assembly(HMODULE hModuleXll, int majorRuntimeVersion, const std::wstring& rollForward, const std::wstring& runtimeFrameworkVersion); // Provide a callback for any catastrophic failures. @@ -54,7 +53,7 @@ void __stdcall preload_runtime(void) {} TempDir tempDir(L"ExcelDna.Host"); // TODO: Might return the fn* -int load_runtime_and_run(const std::wstring& basePath, XlAddInExportInfo* pExportInfo, HMODULE hModuleXll, LPCWSTR pathXll) +int load_and_run(const std::wstring& basePath, XlAddInExportInfo* pExportInfo, HMODULE hModuleXll, LPCWSTR pathXll) { // // STEP 1: Load HostFxr and get exported hosting functions @@ -109,7 +108,7 @@ int load_runtime_and_run(const std::wstring& basePath, XlAddInExportInfo* pExpor hostFile = PathCombine(tempDir.GetPath(), L"ExcelDna.ManagedHost.dll"); if (!std::filesystem::exists(hostFile)) { - int r = write_resource_to_file(hModuleXll, L"EXCELDNA.MANAGEDHOST", L"ASSEMBLY", hostFile); + int r = WriteResourceToFile(hModuleXll, L"EXCELDNA.MANAGEDHOST", L"ASSEMBLY", hostFile); if (r != EXIT_SUCCESS) return r; } @@ -281,7 +280,7 @@ load_assembly_and_get_function_pointer_fn get_dotnet_load_assembly(HMODULE hModu } else { - int r = write_resource_to_file(hModuleXll, L"__CUSTOM_RUNTIMECONFIG__", L"SOURCE", configFile); + int r = WriteResourceToFile(hModuleXll, L"__CUSTOM_RUNTIMECONFIG__", L"SOURCE", configFile); if (r != EXIT_SUCCESS) return nullptr; } @@ -333,43 +332,3 @@ load_assembly_and_get_function_pointer_fn get_dotnet_load_assembly(HMODULE hModu close_fptr(cxt); return (load_assembly_and_get_function_pointer_fn)load_assembly_and_get_function_pointer; } - -int write_resource_to_file(HMODULE hModuleXll, const std::wstring& resourceName, const std::wstring& resourceType, const std::wstring& filePath) -{ - HRSRC hResManagedHost = FindResource(hModuleXll, resourceName.c_str(), resourceType.c_str()); - if (hResManagedHost == NULL) - { - ShowHostError(L"Failure to find resource " + resourceName); - return EXIT_FAILURE; - } - - HGLOBAL hManagedHost = LoadResource(hModuleXll, hResManagedHost); - if (hManagedHost == NULL) - { - ShowHostError(L"Failure to load resource " + resourceName); - return EXIT_FAILURE; - } - - void* buf = LockResource(hManagedHost); - if (buf == NULL) - { - ShowHostError(L"Failure to lock resource " + resourceName); - return EXIT_FAILURE; - } - - DWORD resSize = SizeofResource(hModuleXll, hResManagedHost); - SafeByteArray safeBytes(buf, resSize); - byte* pData; - int nSize = safeBytes.AccessData(&pData); - - HRESULT hr = WriteAllBytes(filePath, pData, nSize); - if (FAILED(hr)) - { - std::wstringstream stream; - stream << L"Saving " << resourceName << L" failed: " << std::hex << std::showbase << hr; - ShowHostError(stream.str()); - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; -} diff --git a/Source/ExcelDna.sln b/Source/ExcelDna.sln index 3d772844..0aa3e1a6 100644 --- a/Source/ExcelDna.sln +++ b/Source/ExcelDna.sln @@ -133,6 +133,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExcelDna.RegistrationTests" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExcelDna.Host.Shared", "ExcelDna.Host.Shared\ExcelDna.Host.Shared.vcxitems", "{65CCAD73-FE1A-47F7-B8AC-3603919C49FE}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExcelDna.Host.NativeAOT", "ExcelDna.Host.NativeAOT\ExcelDna.Host.NativeAOT.vcxproj", "{D50C3A8E-46F1-F61B-C8F5-ECDA05995EEB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -281,6 +283,14 @@ Global {151AE960-6320-402D-BDD0-D76DF96F2BD7}.Release|Win32.Build.0 = Release|Any CPU {151AE960-6320-402D-BDD0-D76DF96F2BD7}.Release|x64.ActiveCfg = Release|Any CPU {151AE960-6320-402D-BDD0-D76DF96F2BD7}.Release|x64.Build.0 = Release|Any CPU + {D50C3A8E-46F1-F61B-C8F5-ECDA05995EEB}.Debug|Win32.ActiveCfg = Debug|Win32 + {D50C3A8E-46F1-F61B-C8F5-ECDA05995EEB}.Debug|Win32.Build.0 = Debug|Win32 + {D50C3A8E-46F1-F61B-C8F5-ECDA05995EEB}.Debug|x64.ActiveCfg = Debug|x64 + {D50C3A8E-46F1-F61B-C8F5-ECDA05995EEB}.Debug|x64.Build.0 = Debug|x64 + {D50C3A8E-46F1-F61B-C8F5-ECDA05995EEB}.Release|Win32.ActiveCfg = Release|Win32 + {D50C3A8E-46F1-F61B-C8F5-ECDA05995EEB}.Release|Win32.Build.0 = Release|Win32 + {D50C3A8E-46F1-F61B-C8F5-ECDA05995EEB}.Release|x64.ActiveCfg = Release|x64 + {D50C3A8E-46F1-F61B-C8F5-ECDA05995EEB}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -309,6 +319,7 @@ Global ExcelDna.PackedResources\ExcelDna.PackedResources.projitems*{7ebb8fa9-a153-422e-b454-144c3fb03450}*SharedItemsImports = 13 ExcelDna.Host.Shared\ExcelDna.Host.Shared.vcxitems*{a9887347-3e93-4e4e-96df-227648e57b60}*SharedItemsImports = 4 ExcelDna.PackedResources\ExcelDna.PackedResources.projitems*{b5cc04d3-0507-4431-9f45-7c60bac3047a}*SharedItemsImports = 5 + ExcelDna.Host.Shared\ExcelDna.Host.Shared.vcxitems*{d50c3a8e-46f1-f61b-c8f5-ecda05995eeb}*SharedItemsImports = 4 ExcelDna.PackedResources\ExcelDna.PackedResources.projitems*{dc10cec8-c6ce-4148-838f-c3dd4ea2a2a3}*SharedItemsImports = 5 ExcelDna.PackedResources\ExcelDna.PackedResources.projitems*{fd7f2ee3-9922-4825-96a2-be2c877baeb9}*SharedItemsImports = 5 EndGlobalSection From 187244db4aa02a714bbc7fb928563b494d714eec Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sun, 19 Jan 2025 15:04:02 +0500 Subject: [PATCH 03/60] Added ExcelDna.SourceGenerator.NativeAOT project. --- .../ExcelDna.SourceGenerator.NativeAOT.csproj | 15 ++++ .../Generator.cs | 71 +++++++++++++++++++ .../Util.cs | 28 ++++++++ Source/ExcelDna.sln | 10 +++ 4 files changed, 124 insertions(+) create mode 100644 Source/ExcelDna.SourceGenerator.NativeAOT/ExcelDna.SourceGenerator.NativeAOT.csproj create mode 100644 Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs create mode 100644 Source/ExcelDna.SourceGenerator.NativeAOT/Util.cs diff --git a/Source/ExcelDna.SourceGenerator.NativeAOT/ExcelDna.SourceGenerator.NativeAOT.csproj b/Source/ExcelDna.SourceGenerator.NativeAOT/ExcelDna.SourceGenerator.NativeAOT.csproj new file mode 100644 index 00000000..77beb14d --- /dev/null +++ b/Source/ExcelDna.SourceGenerator.NativeAOT/ExcelDna.SourceGenerator.NativeAOT.csproj @@ -0,0 +1,15 @@ + + + + netstandard2.0 + enable + preview + true + + + + + + + + diff --git a/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs b/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs new file mode 100644 index 00000000..a6d66531 --- /dev/null +++ b/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs @@ -0,0 +1,71 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace ExcelDna.SourceGenerator.NativeAOT +{ + [Generator] + public class Generator : ISourceGenerator + { + public void Execute(GeneratorExecutionContext context) + { + if (!(context.SyntaxContextReceiver is SyntaxReceiver receiver)) + return; + + context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.PublishAOT", out string? publishAOT); + + string source = """ +// +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace ExcelDna.SourceGenerator.NativeAOT +{ + public unsafe class AddInInitialize + { + [UnmanagedCallersOnly(EntryPoint = "Initialize", CallConvs = new[] { typeof(CallConvCdecl) })] + public static short Initialize(void* xlAddInExportInfoAddress, void* hModuleXll, void* pPathXLL, byte disableAssemblyContextUnload, void* pTempDirPath) + { + [FUNCTIONS] + + return ExcelDna.ManagedHost.AddInInitialize.Initialize(xlAddInExportInfoAddress, hModuleXll, pPathXLL, disableAssemblyContextUnload, pTempDirPath); + } + } +} +"""; + string functions = ""; + foreach (var i in receiver.Functions) + { + functions += $"ExcelDna.Integration.DnaLibrary.MethodsForRegistration.Add(typeof({i.ContainingType}).GetMethod(\"{i.Name}\")!);\r\n"; + } + + source = source.Replace("[FUNCTIONS]", functions); + + context.AddSource($"ExcelDna.SourceGenerator.NativeAOT.Initialize.g.cs", source); + } + + public void Initialize(GeneratorInitializationContext context) + { + context.RegisterForSyntaxNotifications(() => new SyntaxReceiver()); + } + + class SyntaxReceiver : ISyntaxContextReceiver + { + public List Functions { get; } = new List(); + + public void OnVisitSyntaxNode(GeneratorSyntaxContext context) + { + if (context.Node is MethodDeclarationSyntax methodSyntax) + { + IMethodSymbol methodSymbol = (context.SemanticModel.GetDeclaredSymbol(methodSyntax) as IMethodSymbol)!; + if (methodSymbol.GetAttributes().Any(a => a.AttributeClass?.ToDisplayString(fullNameFormat) == "ExcelDna.Integration.ExcelFunctionAttribute")) + Functions.Add(methodSymbol); + } + } + + private static SymbolDisplayFormat fullNameFormat = new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces); + } + } +} diff --git a/Source/ExcelDna.SourceGenerator.NativeAOT/Util.cs b/Source/ExcelDna.SourceGenerator.NativeAOT/Util.cs new file mode 100644 index 00000000..957af58c --- /dev/null +++ b/Source/ExcelDna.SourceGenerator.NativeAOT/Util.cs @@ -0,0 +1,28 @@ +using Microsoft.CodeAnalysis; +using System.Collections.Generic; + +namespace ExcelDna.SourceGenerator.NativeAOT +{ + public class Util + { + public static string GetFullTypeName(ITypeSymbol type) + { + return type.ToDisplayString(); + } + + public static string GetFullMethodName(IMethodSymbol method) + { + return $"{GetFullTypeName(method.ContainingType)}.{method.Name}"; + } + + public static IEnumerable GetBaseTypesAndThis(ITypeSymbol type) + { + var current = type; + while (current != null) + { + yield return current; + current = current.BaseType; + } + } + } +} diff --git a/Source/ExcelDna.sln b/Source/ExcelDna.sln index 0aa3e1a6..564a569b 100644 --- a/Source/ExcelDna.sln +++ b/Source/ExcelDna.sln @@ -135,6 +135,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExcelDna.Host.Shared", "Exc EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExcelDna.Host.NativeAOT", "ExcelDna.Host.NativeAOT\ExcelDna.Host.NativeAOT.vcxproj", "{D50C3A8E-46F1-F61B-C8F5-ECDA05995EEB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExcelDna.SourceGenerator.NativeAOT", "ExcelDna.SourceGenerator.NativeAOT\ExcelDna.SourceGenerator.NativeAOT.csproj", "{DAF494B7-16F3-AAA7-5F71-234663023BB6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -291,6 +293,14 @@ Global {D50C3A8E-46F1-F61B-C8F5-ECDA05995EEB}.Release|Win32.Build.0 = Release|Win32 {D50C3A8E-46F1-F61B-C8F5-ECDA05995EEB}.Release|x64.ActiveCfg = Release|x64 {D50C3A8E-46F1-F61B-C8F5-ECDA05995EEB}.Release|x64.Build.0 = Release|x64 + {DAF494B7-16F3-AAA7-5F71-234663023BB6}.Debug|Win32.ActiveCfg = Debug|Any CPU + {DAF494B7-16F3-AAA7-5F71-234663023BB6}.Debug|Win32.Build.0 = Debug|Any CPU + {DAF494B7-16F3-AAA7-5F71-234663023BB6}.Debug|x64.ActiveCfg = Debug|Any CPU + {DAF494B7-16F3-AAA7-5F71-234663023BB6}.Debug|x64.Build.0 = Debug|Any CPU + {DAF494B7-16F3-AAA7-5F71-234663023BB6}.Release|Win32.ActiveCfg = Release|Any CPU + {DAF494B7-16F3-AAA7-5F71-234663023BB6}.Release|Win32.Build.0 = Release|Any CPU + {DAF494B7-16F3-AAA7-5F71-234663023BB6}.Release|x64.ActiveCfg = Release|Any CPU + {DAF494B7-16F3-AAA7-5F71-234663023BB6}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From b5765151609a2af0a3e57d1e3d24a7e513d4353b Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sat, 25 Jan 2025 17:34:21 +0500 Subject: [PATCH 04/60] Added MethodsForRegistration and InitializeNativeAOT. --- Source/ExcelDna.Integration/DnaLibrary.cs | 3 +++ Source/ExcelDna.Integration/NativeAOT.cs | 10 ++++++++++ Source/ExcelDna.ManagedHost/AddInInitialize.cs | 18 ++++++++++++++++++ .../Generator.cs | 6 +++--- 4 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 Source/ExcelDna.Integration/NativeAOT.cs diff --git a/Source/ExcelDna.Integration/DnaLibrary.cs b/Source/ExcelDna.Integration/DnaLibrary.cs index 00f879af..2465a12d 100644 --- a/Source/ExcelDna.Integration/DnaLibrary.cs +++ b/Source/ExcelDna.Integration/DnaLibrary.cs @@ -322,6 +322,9 @@ internal void AutoOpen() // Register special RegistrationInfo function RegistrationInfo.Register(); SynchronizationManager.Install(true); + + _methods.AddRange(NativeAOT.MethodsForRegistration); + // Register my Methods if (_excelFunctionExecutionHandlerSelectors.Count == 0) ExcelIntegration.RegisterMethods(_methods); diff --git a/Source/ExcelDna.Integration/NativeAOT.cs b/Source/ExcelDna.Integration/NativeAOT.cs new file mode 100644 index 00000000..2c0cce82 --- /dev/null +++ b/Source/ExcelDna.Integration/NativeAOT.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using System.Reflection; + +namespace ExcelDna.Integration +{ + public class NativeAOT + { + public static List MethodsForRegistration { get; } = new List(); + } +} diff --git a/Source/ExcelDna.ManagedHost/AddInInitialize.cs b/Source/ExcelDna.ManagedHost/AddInInitialize.cs index 651eaae8..65012cfd 100644 --- a/Source/ExcelDna.ManagedHost/AddInInitialize.cs +++ b/Source/ExcelDna.ManagedHost/AddInInitialize.cs @@ -56,6 +56,24 @@ public static short Initialize(void* xlAddInExportInfoAddress, void* hModuleXll, return initOK ? (short)1 : (short)0; } + public static short InitializeNativeAOT(void* xlAddInExportInfoAddress, void* hModuleXll, void* pPathXLL, byte disableAssemblyContextUnload, void* pTempDirPath) + { + UnloadALC(); + ProcessStartupHooks(); + + string pathXll = Marshal.PtrToStringUni((IntPtr)pPathXLL); + string tempDirPath = Marshal.PtrToStringUni((IntPtr)pTempDirPath); + _alc = new ExcelDnaAssemblyLoadContext(pathXll, disableAssemblyContextUnload == 0); + AssemblyManager.Initialize((IntPtr)hModuleXll, pathXll, _alc, Path.Combine(tempDirPath, "ExcelDna.ManagedHost.NativeAOT")); + var initOK = (bool)ExcelDna.Loader.XlAddIn.Initialize((IntPtr)xlAddInExportInfoAddress, (IntPtr)hModuleXll, pathXll, tempDirPath, + (Func)AssemblyManager.GetResourceBytes, + (Func)_alc.LoadFromAssemblyPath, + (Func)_alc.LoadFromAssemblyBytes, + (Action)Logger.SetIntegrationTraceSource); + + return initOK ? (short)1 : (short)0; + } + private static void UnloadALC() { if (_alc == null) diff --git a/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs b/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs index a6d66531..3bd1bf60 100644 --- a/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs +++ b/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs @@ -30,7 +30,7 @@ public static short Initialize(void* xlAddInExportInfoAddress, void* hModuleXll, { [FUNCTIONS] - return ExcelDna.ManagedHost.AddInInitialize.Initialize(xlAddInExportInfoAddress, hModuleXll, pPathXLL, disableAssemblyContextUnload, pTempDirPath); + return ExcelDna.ManagedHost.AddInInitialize.InitializeNativeAOT(xlAddInExportInfoAddress, hModuleXll, pPathXLL, disableAssemblyContextUnload, pTempDirPath); } } } @@ -38,12 +38,12 @@ public static short Initialize(void* xlAddInExportInfoAddress, void* hModuleXll, string functions = ""; foreach (var i in receiver.Functions) { - functions += $"ExcelDna.Integration.DnaLibrary.MethodsForRegistration.Add(typeof({i.ContainingType}).GetMethod(\"{i.Name}\")!);\r\n"; + functions += $"ExcelDna.Integration.NativeAOT.MethodsForRegistration.Add(typeof({i.ContainingType}).GetMethod(\"{i.Name}\")!);\r\n"; } source = source.Replace("[FUNCTIONS]", functions); - context.AddSource($"ExcelDna.SourceGenerator.NativeAOT.Initialize.g.cs", source); + context.AddSource($"ExcelDna.SG.NAOT.Init.g.cs", source); } public void Initialize(GeneratorInitializationContext context) From f53775e16f19d2805884a883fac4b88adae0cd6d Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sat, 25 Jan 2025 18:23:41 +0500 Subject: [PATCH 05/60] Disabled AssemblyDependencyResolver when NativeAOT is active. --- Source/ExcelDna.Integration/NativeAOT.cs | 2 ++ .../ExcelDna.ManagedHost/ExcelDnaAssemblyLoadContext.cs | 8 +++++--- Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs | 2 ++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Source/ExcelDna.Integration/NativeAOT.cs b/Source/ExcelDna.Integration/NativeAOT.cs index 2c0cce82..316ca178 100644 --- a/Source/ExcelDna.Integration/NativeAOT.cs +++ b/Source/ExcelDna.Integration/NativeAOT.cs @@ -5,6 +5,8 @@ namespace ExcelDna.Integration { public class NativeAOT { + public static bool IsActive { get; set; } + public static List MethodsForRegistration { get; } = new List(); } } diff --git a/Source/ExcelDna.ManagedHost/ExcelDnaAssemblyLoadContext.cs b/Source/ExcelDna.ManagedHost/ExcelDnaAssemblyLoadContext.cs index 6f8a163e..dd3a6a5a 100644 --- a/Source/ExcelDna.ManagedHost/ExcelDnaAssemblyLoadContext.cs +++ b/Source/ExcelDna.ManagedHost/ExcelDnaAssemblyLoadContext.cs @@ -18,7 +18,9 @@ public ExcelDnaAssemblyLoadContext(string basePath, bool isCollectible) : base($"ExcelDnaAssemblyLoadContext_{Path.GetFileNameWithoutExtension(basePath)}", isCollectible: isCollectible) { _basePath = basePath; - _resolver = new AssemblyDependencyResolver(basePath); + + if (!ExcelDna.Integration.NativeAOT.IsActive) + _resolver = new AssemblyDependencyResolver(basePath); #if DEBUG this.Resolving += ExcelDnaAssemblyLoadContext_Resolving; @@ -31,7 +33,7 @@ protected override Assembly Load(AssemblyName assemblyName) // CONSIDER: Should we consider priorities for packed vs local files? // First try the regular load path - string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName); + string assemblyPath = _resolver?.ResolveAssemblyToPath(assemblyName); if (assemblyPath != null) { return LoadFromAssemblyPath(assemblyPath); @@ -48,7 +50,7 @@ protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) libraryPath = cachedValue; if (libraryPath == null) - libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName); + libraryPath = _resolver?.ResolveUnmanagedDllToPath(unmanagedDllName); if (libraryPath == null) libraryPath = ResolveDllFromBaseDirectory(unmanagedDllName); diff --git a/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs b/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs index 3bd1bf60..c5466e7c 100644 --- a/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs +++ b/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs @@ -28,6 +28,8 @@ public unsafe class AddInInitialize [UnmanagedCallersOnly(EntryPoint = "Initialize", CallConvs = new[] { typeof(CallConvCdecl) })] public static short Initialize(void* xlAddInExportInfoAddress, void* hModuleXll, void* pPathXLL, byte disableAssemblyContextUnload, void* pTempDirPath) { + ExcelDna.Integration.NativeAOT.IsActive = true; + [FUNCTIONS] return ExcelDna.ManagedHost.AddInInitialize.InitializeNativeAOT(xlAddInExportInfoAddress, hModuleXll, pPathXLL, disableAssemblyContextUnload, pTempDirPath); From 6e0667cc3f3d890e9f2d190e6861a0bc0563fe32 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sat, 25 Jan 2025 21:49:18 +0500 Subject: [PATCH 06/60] Added function marshaling for NativeAOT. --- Source/ExcelDna.Loader/MarshalNativeAOT.cs | 533 +++++++++++++++++++++ Source/ExcelDna.Loader/XlDirectMarshal.cs | 5 +- 2 files changed, 537 insertions(+), 1 deletion(-) create mode 100644 Source/ExcelDna.Loader/MarshalNativeAOT.cs diff --git a/Source/ExcelDna.Loader/MarshalNativeAOT.cs b/Source/ExcelDna.Loader/MarshalNativeAOT.cs new file mode 100644 index 00000000..f671ce1b --- /dev/null +++ b/Source/ExcelDna.Loader/MarshalNativeAOT.cs @@ -0,0 +1,533 @@ +using System; +using System.Runtime.InteropServices; +using static ExcelDna.Loader.XlDirectMarshalTypes; + +namespace ExcelDna.Loader +{ + class MarshalNativeAOT + { + public static IntPtr GetFunctionPointerForDelegate(Delegate d, XlMethodInfo methodInfo) + { + if (methodInfo.HasReturnType) + { + switch (methodInfo.Parameters.Length) + { + case 0: + return Marshal.GetFunctionPointerForDelegate((XlFunc0)d); + case 1: + return Marshal.GetFunctionPointerForDelegate((XlFunc1)d); + case 2: + return Marshal.GetFunctionPointerForDelegate((XlFunc2)d); + case 3: + return Marshal.GetFunctionPointerForDelegate((XlFunc3)d); + case 4: + return Marshal.GetFunctionPointerForDelegate((XlFunc4)d); + case 5: + return Marshal.GetFunctionPointerForDelegate((XlFunc5)d); + case 6: + return Marshal.GetFunctionPointerForDelegate((XlFunc6)d); + case 7: + return Marshal.GetFunctionPointerForDelegate((XlFunc7)d); + case 8: + return Marshal.GetFunctionPointerForDelegate((XlFunc8)d); + case 9: + return Marshal.GetFunctionPointerForDelegate((XlFunc9)d); + case 10: + return Marshal.GetFunctionPointerForDelegate((XlFunc10)d); + case 11: + return Marshal.GetFunctionPointerForDelegate((XlFunc11)d); + case 12: + return Marshal.GetFunctionPointerForDelegate((XlFunc12)d); + case 13: + return Marshal.GetFunctionPointerForDelegate((XlFunc13)d); + case 14: + return Marshal.GetFunctionPointerForDelegate((XlFunc14)d); + case 15: + return Marshal.GetFunctionPointerForDelegate((XlFunc15)d); + case 16: + return Marshal.GetFunctionPointerForDelegate((XlFunc16)d); + case 17: + return Marshal.GetFunctionPointerForDelegate((XlFunc17)d); + case 18: + return Marshal.GetFunctionPointerForDelegate((XlFunc18)d); + case 19: + return Marshal.GetFunctionPointerForDelegate((XlFunc19)d); + case 20: + return Marshal.GetFunctionPointerForDelegate((XlFunc20)d); + case 21: + return Marshal.GetFunctionPointerForDelegate((XlFunc21)d); + case 22: + return Marshal.GetFunctionPointerForDelegate((XlFunc22)d); + case 23: + return Marshal.GetFunctionPointerForDelegate((XlFunc23)d); + case 24: + return Marshal.GetFunctionPointerForDelegate((XlFunc24)d); + case 25: + return Marshal.GetFunctionPointerForDelegate((XlFunc25)d); + case 26: + return Marshal.GetFunctionPointerForDelegate((XlFunc26)d); + case 27: + return Marshal.GetFunctionPointerForDelegate((XlFunc27)d); + case 28: + return Marshal.GetFunctionPointerForDelegate((XlFunc28)d); + case 29: + return Marshal.GetFunctionPointerForDelegate((XlFunc29)d); + case 30: + return Marshal.GetFunctionPointerForDelegate((XlFunc30)d); + case 31: + return Marshal.GetFunctionPointerForDelegate((XlFunc31)d); + case 32: + return Marshal.GetFunctionPointerForDelegate((XlFunc32)d); + case 33: + return Marshal.GetFunctionPointerForDelegate((XlFunc33)d); + case 34: + return Marshal.GetFunctionPointerForDelegate((XlFunc34)d); + case 35: + return Marshal.GetFunctionPointerForDelegate((XlFunc35)d); + case 36: + return Marshal.GetFunctionPointerForDelegate((XlFunc36)d); + case 37: + return Marshal.GetFunctionPointerForDelegate((XlFunc37)d); + case 38: + return Marshal.GetFunctionPointerForDelegate((XlFunc38)d); + case 39: + return Marshal.GetFunctionPointerForDelegate((XlFunc39)d); + case 40: + return Marshal.GetFunctionPointerForDelegate((XlFunc40)d); + case 41: + return Marshal.GetFunctionPointerForDelegate((XlFunc41)d); + case 42: + return Marshal.GetFunctionPointerForDelegate((XlFunc42)d); + case 43: + return Marshal.GetFunctionPointerForDelegate((XlFunc43)d); + case 44: + return Marshal.GetFunctionPointerForDelegate((XlFunc44)d); + case 45: + return Marshal.GetFunctionPointerForDelegate((XlFunc45)d); + case 46: + return Marshal.GetFunctionPointerForDelegate((XlFunc46)d); + case 47: + return Marshal.GetFunctionPointerForDelegate((XlFunc47)d); + case 48: + return Marshal.GetFunctionPointerForDelegate((XlFunc48)d); + case 49: + return Marshal.GetFunctionPointerForDelegate((XlFunc49)d); + case 50: + return Marshal.GetFunctionPointerForDelegate((XlFunc50)d); + case 51: + return Marshal.GetFunctionPointerForDelegate((XlFunc51)d); + case 52: + return Marshal.GetFunctionPointerForDelegate((XlFunc52)d); + case 53: + return Marshal.GetFunctionPointerForDelegate((XlFunc53)d); + case 54: + return Marshal.GetFunctionPointerForDelegate((XlFunc54)d); + case 55: + return Marshal.GetFunctionPointerForDelegate((XlFunc55)d); + case 56: + return Marshal.GetFunctionPointerForDelegate((XlFunc56)d); + case 57: + return Marshal.GetFunctionPointerForDelegate((XlFunc57)d); + case 58: + return Marshal.GetFunctionPointerForDelegate((XlFunc58)d); + case 59: + return Marshal.GetFunctionPointerForDelegate((XlFunc59)d); + case 60: + return Marshal.GetFunctionPointerForDelegate((XlFunc60)d); + case 61: + return Marshal.GetFunctionPointerForDelegate((XlFunc61)d); + case 62: + return Marshal.GetFunctionPointerForDelegate((XlFunc62)d); + case 63: + return Marshal.GetFunctionPointerForDelegate((XlFunc63)d); + case 64: + return Marshal.GetFunctionPointerForDelegate((XlFunc64)d); + case 65: + return Marshal.GetFunctionPointerForDelegate((XlFunc65)d); + case 66: + return Marshal.GetFunctionPointerForDelegate((XlFunc66)d); + case 67: + return Marshal.GetFunctionPointerForDelegate((XlFunc67)d); + case 68: + return Marshal.GetFunctionPointerForDelegate((XlFunc68)d); + case 69: + return Marshal.GetFunctionPointerForDelegate((XlFunc69)d); + case 70: + return Marshal.GetFunctionPointerForDelegate((XlFunc70)d); + case 71: + return Marshal.GetFunctionPointerForDelegate((XlFunc71)d); + case 72: + return Marshal.GetFunctionPointerForDelegate((XlFunc72)d); + case 73: + return Marshal.GetFunctionPointerForDelegate((XlFunc73)d); + case 74: + return Marshal.GetFunctionPointerForDelegate((XlFunc74)d); + case 75: + return Marshal.GetFunctionPointerForDelegate((XlFunc75)d); + case 76: + return Marshal.GetFunctionPointerForDelegate((XlFunc76)d); + case 77: + return Marshal.GetFunctionPointerForDelegate((XlFunc77)d); + case 78: + return Marshal.GetFunctionPointerForDelegate((XlFunc78)d); + case 79: + return Marshal.GetFunctionPointerForDelegate((XlFunc79)d); + case 80: + return Marshal.GetFunctionPointerForDelegate((XlFunc80)d); + case 81: + return Marshal.GetFunctionPointerForDelegate((XlFunc81)d); + case 82: + return Marshal.GetFunctionPointerForDelegate((XlFunc82)d); + case 83: + return Marshal.GetFunctionPointerForDelegate((XlFunc83)d); + case 84: + return Marshal.GetFunctionPointerForDelegate((XlFunc84)d); + case 85: + return Marshal.GetFunctionPointerForDelegate((XlFunc85)d); + case 86: + return Marshal.GetFunctionPointerForDelegate((XlFunc86)d); + case 87: + return Marshal.GetFunctionPointerForDelegate((XlFunc87)d); + case 88: + return Marshal.GetFunctionPointerForDelegate((XlFunc88)d); + case 89: + return Marshal.GetFunctionPointerForDelegate((XlFunc89)d); + case 90: + return Marshal.GetFunctionPointerForDelegate((XlFunc90)d); + case 91: + return Marshal.GetFunctionPointerForDelegate((XlFunc91)d); + case 92: + return Marshal.GetFunctionPointerForDelegate((XlFunc92)d); + case 93: + return Marshal.GetFunctionPointerForDelegate((XlFunc93)d); + case 94: + return Marshal.GetFunctionPointerForDelegate((XlFunc94)d); + case 95: + return Marshal.GetFunctionPointerForDelegate((XlFunc95)d); + case 96: + return Marshal.GetFunctionPointerForDelegate((XlFunc96)d); + case 97: + return Marshal.GetFunctionPointerForDelegate((XlFunc97)d); + case 98: + return Marshal.GetFunctionPointerForDelegate((XlFunc98)d); + case 99: + return Marshal.GetFunctionPointerForDelegate((XlFunc99)d); + case 100: + return Marshal.GetFunctionPointerForDelegate((XlFunc100)d); + case 101: + return Marshal.GetFunctionPointerForDelegate((XlFunc101)d); + case 102: + return Marshal.GetFunctionPointerForDelegate((XlFunc102)d); + case 103: + return Marshal.GetFunctionPointerForDelegate((XlFunc103)d); + case 104: + return Marshal.GetFunctionPointerForDelegate((XlFunc104)d); + case 105: + return Marshal.GetFunctionPointerForDelegate((XlFunc105)d); + case 106: + return Marshal.GetFunctionPointerForDelegate((XlFunc106)d); + case 107: + return Marshal.GetFunctionPointerForDelegate((XlFunc107)d); + case 108: + return Marshal.GetFunctionPointerForDelegate((XlFunc108)d); + case 109: + return Marshal.GetFunctionPointerForDelegate((XlFunc109)d); + case 110: + return Marshal.GetFunctionPointerForDelegate((XlFunc110)d); + case 111: + return Marshal.GetFunctionPointerForDelegate((XlFunc111)d); + case 112: + return Marshal.GetFunctionPointerForDelegate((XlFunc112)d); + case 113: + return Marshal.GetFunctionPointerForDelegate((XlFunc113)d); + case 114: + return Marshal.GetFunctionPointerForDelegate((XlFunc114)d); + case 115: + return Marshal.GetFunctionPointerForDelegate((XlFunc115)d); + case 116: + return Marshal.GetFunctionPointerForDelegate((XlFunc116)d); + case 117: + return Marshal.GetFunctionPointerForDelegate((XlFunc117)d); + case 118: + return Marshal.GetFunctionPointerForDelegate((XlFunc118)d); + case 119: + return Marshal.GetFunctionPointerForDelegate((XlFunc119)d); + case 120: + return Marshal.GetFunctionPointerForDelegate((XlFunc120)d); + case 121: + return Marshal.GetFunctionPointerForDelegate((XlFunc121)d); + case 122: + return Marshal.GetFunctionPointerForDelegate((XlFunc122)d); + case 123: + return Marshal.GetFunctionPointerForDelegate((XlFunc123)d); + case 124: + return Marshal.GetFunctionPointerForDelegate((XlFunc124)d); + case 125: + return Marshal.GetFunctionPointerForDelegate((XlFunc125)d); + case 126: + return Marshal.GetFunctionPointerForDelegate((XlFunc126)d); + case 127: + return Marshal.GetFunctionPointerForDelegate((XlFunc127)d); + case 128: + return Marshal.GetFunctionPointerForDelegate((XlFunc128)d); + case 129: + return Marshal.GetFunctionPointerForDelegate((XlFunc129)d); + case 130: + return Marshal.GetFunctionPointerForDelegate((XlFunc130)d); + case 131: + return Marshal.GetFunctionPointerForDelegate((XlFunc131)d); + case 132: + return Marshal.GetFunctionPointerForDelegate((XlFunc132)d); + case 133: + return Marshal.GetFunctionPointerForDelegate((XlFunc133)d); + case 134: + return Marshal.GetFunctionPointerForDelegate((XlFunc134)d); + case 135: + return Marshal.GetFunctionPointerForDelegate((XlFunc135)d); + case 136: + return Marshal.GetFunctionPointerForDelegate((XlFunc136)d); + case 137: + return Marshal.GetFunctionPointerForDelegate((XlFunc137)d); + case 138: + return Marshal.GetFunctionPointerForDelegate((XlFunc138)d); + case 139: + return Marshal.GetFunctionPointerForDelegate((XlFunc139)d); + case 140: + return Marshal.GetFunctionPointerForDelegate((XlFunc140)d); + case 141: + return Marshal.GetFunctionPointerForDelegate((XlFunc141)d); + case 142: + return Marshal.GetFunctionPointerForDelegate((XlFunc142)d); + case 143: + return Marshal.GetFunctionPointerForDelegate((XlFunc143)d); + case 144: + return Marshal.GetFunctionPointerForDelegate((XlFunc144)d); + case 145: + return Marshal.GetFunctionPointerForDelegate((XlFunc145)d); + case 146: + return Marshal.GetFunctionPointerForDelegate((XlFunc146)d); + case 147: + return Marshal.GetFunctionPointerForDelegate((XlFunc147)d); + case 148: + return Marshal.GetFunctionPointerForDelegate((XlFunc148)d); + case 149: + return Marshal.GetFunctionPointerForDelegate((XlFunc149)d); + case 150: + return Marshal.GetFunctionPointerForDelegate((XlFunc150)d); + case 151: + return Marshal.GetFunctionPointerForDelegate((XlFunc151)d); + case 152: + return Marshal.GetFunctionPointerForDelegate((XlFunc152)d); + case 153: + return Marshal.GetFunctionPointerForDelegate((XlFunc153)d); + case 154: + return Marshal.GetFunctionPointerForDelegate((XlFunc154)d); + case 155: + return Marshal.GetFunctionPointerForDelegate((XlFunc155)d); + case 156: + return Marshal.GetFunctionPointerForDelegate((XlFunc156)d); + case 157: + return Marshal.GetFunctionPointerForDelegate((XlFunc157)d); + case 158: + return Marshal.GetFunctionPointerForDelegate((XlFunc158)d); + case 159: + return Marshal.GetFunctionPointerForDelegate((XlFunc159)d); + case 160: + return Marshal.GetFunctionPointerForDelegate((XlFunc160)d); + case 161: + return Marshal.GetFunctionPointerForDelegate((XlFunc161)d); + case 162: + return Marshal.GetFunctionPointerForDelegate((XlFunc162)d); + case 163: + return Marshal.GetFunctionPointerForDelegate((XlFunc163)d); + case 164: + return Marshal.GetFunctionPointerForDelegate((XlFunc164)d); + case 165: + return Marshal.GetFunctionPointerForDelegate((XlFunc165)d); + case 166: + return Marshal.GetFunctionPointerForDelegate((XlFunc166)d); + case 167: + return Marshal.GetFunctionPointerForDelegate((XlFunc167)d); + case 168: + return Marshal.GetFunctionPointerForDelegate((XlFunc168)d); + case 169: + return Marshal.GetFunctionPointerForDelegate((XlFunc169)d); + case 170: + return Marshal.GetFunctionPointerForDelegate((XlFunc170)d); + case 171: + return Marshal.GetFunctionPointerForDelegate((XlFunc171)d); + case 172: + return Marshal.GetFunctionPointerForDelegate((XlFunc172)d); + case 173: + return Marshal.GetFunctionPointerForDelegate((XlFunc173)d); + case 174: + return Marshal.GetFunctionPointerForDelegate((XlFunc174)d); + case 175: + return Marshal.GetFunctionPointerForDelegate((XlFunc175)d); + case 176: + return Marshal.GetFunctionPointerForDelegate((XlFunc176)d); + case 177: + return Marshal.GetFunctionPointerForDelegate((XlFunc177)d); + case 178: + return Marshal.GetFunctionPointerForDelegate((XlFunc178)d); + case 179: + return Marshal.GetFunctionPointerForDelegate((XlFunc179)d); + case 180: + return Marshal.GetFunctionPointerForDelegate((XlFunc180)d); + case 181: + return Marshal.GetFunctionPointerForDelegate((XlFunc181)d); + case 182: + return Marshal.GetFunctionPointerForDelegate((XlFunc182)d); + case 183: + return Marshal.GetFunctionPointerForDelegate((XlFunc183)d); + case 184: + return Marshal.GetFunctionPointerForDelegate((XlFunc184)d); + case 185: + return Marshal.GetFunctionPointerForDelegate((XlFunc185)d); + case 186: + return Marshal.GetFunctionPointerForDelegate((XlFunc186)d); + case 187: + return Marshal.GetFunctionPointerForDelegate((XlFunc187)d); + case 188: + return Marshal.GetFunctionPointerForDelegate((XlFunc188)d); + case 189: + return Marshal.GetFunctionPointerForDelegate((XlFunc189)d); + case 190: + return Marshal.GetFunctionPointerForDelegate((XlFunc190)d); + case 191: + return Marshal.GetFunctionPointerForDelegate((XlFunc191)d); + case 192: + return Marshal.GetFunctionPointerForDelegate((XlFunc192)d); + case 193: + return Marshal.GetFunctionPointerForDelegate((XlFunc193)d); + case 194: + return Marshal.GetFunctionPointerForDelegate((XlFunc194)d); + case 195: + return Marshal.GetFunctionPointerForDelegate((XlFunc195)d); + case 196: + return Marshal.GetFunctionPointerForDelegate((XlFunc196)d); + case 197: + return Marshal.GetFunctionPointerForDelegate((XlFunc197)d); + case 198: + return Marshal.GetFunctionPointerForDelegate((XlFunc198)d); + case 199: + return Marshal.GetFunctionPointerForDelegate((XlFunc199)d); + case 200: + return Marshal.GetFunctionPointerForDelegate((XlFunc200)d); + case 201: + return Marshal.GetFunctionPointerForDelegate((XlFunc201)d); + case 202: + return Marshal.GetFunctionPointerForDelegate((XlFunc202)d); + case 203: + return Marshal.GetFunctionPointerForDelegate((XlFunc203)d); + case 204: + return Marshal.GetFunctionPointerForDelegate((XlFunc204)d); + case 205: + return Marshal.GetFunctionPointerForDelegate((XlFunc205)d); + case 206: + return Marshal.GetFunctionPointerForDelegate((XlFunc206)d); + case 207: + return Marshal.GetFunctionPointerForDelegate((XlFunc207)d); + case 208: + return Marshal.GetFunctionPointerForDelegate((XlFunc208)d); + case 209: + return Marshal.GetFunctionPointerForDelegate((XlFunc209)d); + case 210: + return Marshal.GetFunctionPointerForDelegate((XlFunc210)d); + case 211: + return Marshal.GetFunctionPointerForDelegate((XlFunc211)d); + case 212: + return Marshal.GetFunctionPointerForDelegate((XlFunc212)d); + case 213: + return Marshal.GetFunctionPointerForDelegate((XlFunc213)d); + case 214: + return Marshal.GetFunctionPointerForDelegate((XlFunc214)d); + case 215: + return Marshal.GetFunctionPointerForDelegate((XlFunc215)d); + case 216: + return Marshal.GetFunctionPointerForDelegate((XlFunc216)d); + case 217: + return Marshal.GetFunctionPointerForDelegate((XlFunc217)d); + case 218: + return Marshal.GetFunctionPointerForDelegate((XlFunc218)d); + case 219: + return Marshal.GetFunctionPointerForDelegate((XlFunc219)d); + case 220: + return Marshal.GetFunctionPointerForDelegate((XlFunc220)d); + case 221: + return Marshal.GetFunctionPointerForDelegate((XlFunc221)d); + case 222: + return Marshal.GetFunctionPointerForDelegate((XlFunc222)d); + case 223: + return Marshal.GetFunctionPointerForDelegate((XlFunc223)d); + case 224: + return Marshal.GetFunctionPointerForDelegate((XlFunc224)d); + case 225: + return Marshal.GetFunctionPointerForDelegate((XlFunc225)d); + case 226: + return Marshal.GetFunctionPointerForDelegate((XlFunc226)d); + case 227: + return Marshal.GetFunctionPointerForDelegate((XlFunc227)d); + case 228: + return Marshal.GetFunctionPointerForDelegate((XlFunc228)d); + case 229: + return Marshal.GetFunctionPointerForDelegate((XlFunc229)d); + case 230: + return Marshal.GetFunctionPointerForDelegate((XlFunc230)d); + case 231: + return Marshal.GetFunctionPointerForDelegate((XlFunc231)d); + case 232: + return Marshal.GetFunctionPointerForDelegate((XlFunc232)d); + case 233: + return Marshal.GetFunctionPointerForDelegate((XlFunc233)d); + case 234: + return Marshal.GetFunctionPointerForDelegate((XlFunc234)d); + case 235: + return Marshal.GetFunctionPointerForDelegate((XlFunc235)d); + case 236: + return Marshal.GetFunctionPointerForDelegate((XlFunc236)d); + case 237: + return Marshal.GetFunctionPointerForDelegate((XlFunc237)d); + case 238: + return Marshal.GetFunctionPointerForDelegate((XlFunc238)d); + case 239: + return Marshal.GetFunctionPointerForDelegate((XlFunc239)d); + case 240: + return Marshal.GetFunctionPointerForDelegate((XlFunc240)d); + case 241: + return Marshal.GetFunctionPointerForDelegate((XlFunc241)d); + case 242: + return Marshal.GetFunctionPointerForDelegate((XlFunc242)d); + case 243: + return Marshal.GetFunctionPointerForDelegate((XlFunc243)d); + case 244: + return Marshal.GetFunctionPointerForDelegate((XlFunc244)d); + case 245: + return Marshal.GetFunctionPointerForDelegate((XlFunc245)d); + case 246: + return Marshal.GetFunctionPointerForDelegate((XlFunc246)d); + case 247: + return Marshal.GetFunctionPointerForDelegate((XlFunc247)d); + case 248: + return Marshal.GetFunctionPointerForDelegate((XlFunc248)d); + case 249: + return Marshal.GetFunctionPointerForDelegate((XlFunc249)d); + case 250: + return Marshal.GetFunctionPointerForDelegate((XlFunc250)d); + case 251: + return Marshal.GetFunctionPointerForDelegate((XlFunc251)d); + case 252: + return Marshal.GetFunctionPointerForDelegate((XlFunc252)d); + case 253: + return Marshal.GetFunctionPointerForDelegate((XlFunc253)d); + case 254: + return Marshal.GetFunctionPointerForDelegate((XlFunc254)d); + case 255: + return Marshal.GetFunctionPointerForDelegate((XlFunc255)d); + } + } + + throw new NotImplementedException("GetFunctionPointerForDelegate"); + } + } +} diff --git a/Source/ExcelDna.Loader/XlDirectMarshal.cs b/Source/ExcelDna.Loader/XlDirectMarshal.cs index 64b97519..8f8c1bd6 100644 --- a/Source/ExcelDna.Loader/XlDirectMarshal.cs +++ b/Source/ExcelDna.Loader/XlDirectMarshal.cs @@ -29,7 +29,10 @@ public static void SetDelegateAndFunctionPointer(XlMethodInfo methodInfo) //var xlDelegate = GetNativeDelegate(methodInfo); var xlDelegate = GetLazyDelegate(methodInfo); methodInfo.DelegateHandle = GCHandle.Alloc(xlDelegate); - methodInfo.FunctionPointer = Marshal.GetFunctionPointerForDelegate(xlDelegate); + if (NativeAOT.IsActive) + methodInfo.FunctionPointer = MarshalNativeAOT.GetFunctionPointerForDelegate(xlDelegate, methodInfo); + else + methodInfo.FunctionPointer = Marshal.GetFunctionPointerForDelegate(xlDelegate); } // NOTE: This is called in parallel, from a ThreadPool thread From 6366eff5edbc7428661963f708499b45f4b27553 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sat, 25 Jan 2025 22:05:50 +0500 Subject: [PATCH 07/60] Disabled unnecessary logging errors for NativeAOT. --- Source/ExcelDna.Integration/DnaLibrary.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/ExcelDna.Integration/DnaLibrary.cs b/Source/ExcelDna.Integration/DnaLibrary.cs index 2465a12d..f3d158cc 100644 --- a/Source/ExcelDna.Integration/DnaLibrary.cs +++ b/Source/ExcelDna.Integration/DnaLibrary.cs @@ -503,7 +503,8 @@ internal static void InitializeRootLibrary(string xllPath) // If there have been problems, ensure that there is at lease some current library. if (rootLibrary == null) { - Logger.Initialization.Error("No Dna Library found."); + if (!NativeAOT.IsActive) + Logger.Initialization.Error("No Dna Library found."); rootLibrary = new DnaLibrary(); } @@ -545,7 +546,8 @@ public static DnaLibrary LoadFrom(string fileName) if (!File.Exists(fileName)) { - Logger.Initialization.Error("The required .dna script file {0} does not exist.", fileName); + if (!NativeAOT.IsActive) + Logger.Initialization.Error("The required .dna script file {0} does not exist.", fileName); return null; } From 2f66ddfcebc5e3926f10a37d4898ca2feaf92abc Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sun, 26 Jan 2025 10:23:38 +0500 Subject: [PATCH 08/60] Added ExcelDna.AddIn.RuntimeTestsAOT project and tests. --- Source/ExcelDna.sln | 11 ++++++ .../ExcelDna.AddIn.RuntimeTestsAOT.csproj | 36 +++++++++++++++++++ .../Functions.cs | 19 ++++++++++ .../Tests/ExcelDna.RuntimeTests/NativeAOT.cs | 26 ++++++++++++++ 4 files changed, 92 insertions(+) create mode 100644 Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/ExcelDna.AddIn.RuntimeTestsAOT.csproj create mode 100644 Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/Functions.cs create mode 100644 Source/Tests/ExcelDna.RuntimeTests/NativeAOT.cs diff --git a/Source/ExcelDna.sln b/Source/ExcelDna.sln index 564a569b..2ea2c5d2 100644 --- a/Source/ExcelDna.sln +++ b/Source/ExcelDna.sln @@ -137,6 +137,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExcelDna.Host.NativeAOT", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExcelDna.SourceGenerator.NativeAOT", "ExcelDna.SourceGenerator.NativeAOT\ExcelDna.SourceGenerator.NativeAOT.csproj", "{DAF494B7-16F3-AAA7-5F71-234663023BB6}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExcelDna.AddIn.RuntimeTestsAOT", "Tests\ExcelDna.AddIn.RuntimeTestsAOT\ExcelDna.AddIn.RuntimeTestsAOT.csproj", "{1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -301,6 +303,14 @@ Global {DAF494B7-16F3-AAA7-5F71-234663023BB6}.Release|Win32.Build.0 = Release|Any CPU {DAF494B7-16F3-AAA7-5F71-234663023BB6}.Release|x64.ActiveCfg = Release|Any CPU {DAF494B7-16F3-AAA7-5F71-234663023BB6}.Release|x64.Build.0 = Release|Any CPU + {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Debug|Win32.ActiveCfg = Debug|Any CPU + {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Debug|Win32.Build.0 = Debug|Any CPU + {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Debug|x64.ActiveCfg = Debug|Any CPU + {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Debug|x64.Build.0 = Debug|Any CPU + {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Release|Win32.ActiveCfg = Release|Any CPU + {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Release|Win32.Build.0 = Release|Any CPU + {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Release|x64.ActiveCfg = Release|Any CPU + {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -319,6 +329,7 @@ Global {2F5539CC-E302-49B6-88A9-9264DC6413B3} = {511CE610-5E55-457F-B818-1522D1A96727} {7CA501E1-FB74-4903-B34D-EFE513C5B428} = {511CE610-5E55-457F-B818-1522D1A96727} {151AE960-6320-402D-BDD0-D76DF96F2BD7} = {511CE610-5E55-457F-B818-1522D1A96727} + {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F} = {511CE610-5E55-457F-B818-1522D1A96727} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {69EF43B0-B903-4775-BC81-C7E7E012EDA3} diff --git a/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/ExcelDna.AddIn.RuntimeTestsAOT.csproj b/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/ExcelDna.AddIn.RuntimeTestsAOT.csproj new file mode 100644 index 00000000..d64024d1 --- /dev/null +++ b/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/ExcelDna.AddIn.RuntimeTestsAOT.csproj @@ -0,0 +1,36 @@ + + + + net8.0-windows + true + + win-x64 + true + ExcelDna.AddIn.RuntimeTestsAOT64 + + true + true + + enable + enable + + true + + + + + true + + + + + + + + + + + + + + diff --git a/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/Functions.cs b/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/Functions.cs new file mode 100644 index 00000000..c7b2c0d1 --- /dev/null +++ b/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/Functions.cs @@ -0,0 +1,19 @@ +using ExcelDna.Integration; + +namespace ExcelDna.AddIn.RuntimeTestsAOT +{ + public class Functions + { + [ExcelFunction] + public static string NativeHello(string name) + { + return $"Hello {name}!"; + } + + [ExcelFunction] + public static int NativeSum(int i1, int i2) + { + return i1 + i2; + } + } +} diff --git a/Source/Tests/ExcelDna.RuntimeTests/NativeAOT.cs b/Source/Tests/ExcelDna.RuntimeTests/NativeAOT.cs new file mode 100644 index 00000000..3196214f --- /dev/null +++ b/Source/Tests/ExcelDna.RuntimeTests/NativeAOT.cs @@ -0,0 +1,26 @@ +using Microsoft.Office.Interop.Excel; +using Range = Microsoft.Office.Interop.Excel.Range; + +namespace ExcelDna.RuntimeTests +{ +#if DEBUG + public class NativeAOT + { + [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTestsAOT\bin\Debug\net8.0-windows\win-x64\publish\ExcelDna.AddIn.RuntimeTestsAOT")] + public void Hello() + { + Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1:B1"]; + functionRange.Formula = "=NativeHello(\"world\")"; + Assert.Equal("Hello world!", functionRange.Value.ToString()); + } + + [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTestsAOT\bin\Debug\net8.0-windows\win-x64\publish\ExcelDna.AddIn.RuntimeTestsAOT")] + public void Sum() + { + Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1:B1"]; + functionRange.Formula = "=NativeSum(3, 4)"; + Assert.Equal("7", functionRange.Value.ToString()); + } + } +#endif +} From f40ee2d12af320f6257b6647fbcd84e32fc09545 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sun, 26 Jan 2025 10:58:58 +0500 Subject: [PATCH 09/60] Fixed ManagedHost dependency on Integration. --- Source/ExcelDna.ManagedHost/ExcelDnaAssemblyLoadContext.cs | 2 +- Source/ExcelDna.sln | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Source/ExcelDna.ManagedHost/ExcelDnaAssemblyLoadContext.cs b/Source/ExcelDna.ManagedHost/ExcelDnaAssemblyLoadContext.cs index dd3a6a5a..651df84d 100644 --- a/Source/ExcelDna.ManagedHost/ExcelDnaAssemblyLoadContext.cs +++ b/Source/ExcelDna.ManagedHost/ExcelDnaAssemblyLoadContext.cs @@ -19,7 +19,7 @@ public ExcelDnaAssemblyLoadContext(string basePath, bool isCollectible) { _basePath = basePath; - if (!ExcelDna.Integration.NativeAOT.IsActive) + if (System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported) _resolver = new AssemblyDependencyResolver(basePath); #if DEBUG diff --git a/Source/ExcelDna.sln b/Source/ExcelDna.sln index 2ea2c5d2..b310909c 100644 --- a/Source/ExcelDna.sln +++ b/Source/ExcelDna.sln @@ -138,6 +138,11 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExcelDna.SourceGenerator.NativeAOT", "ExcelDna.SourceGenerator.NativeAOT\ExcelDna.SourceGenerator.NativeAOT.csproj", "{DAF494B7-16F3-AAA7-5F71-234663023BB6}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExcelDna.AddIn.RuntimeTestsAOT", "Tests\ExcelDna.AddIn.RuntimeTestsAOT\ExcelDna.AddIn.RuntimeTestsAOT.csproj", "{1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}" + ProjectSection(ProjectDependencies) = postProject + {196735BC-5A5C-4A21-9FE4-EC01CB7F3DE9} = {196735BC-5A5C-4A21-9FE4-EC01CB7F3DE9} + {59AE5BC6-F37E-4CE3-BAE3-796F807A9882} = {59AE5BC6-F37E-4CE3-BAE3-796F807A9882} + {D50C3A8E-46F1-F61B-C8F5-ECDA05995EEB} = {D50C3A8E-46F1-F61B-C8F5-ECDA05995EEB} + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From 935505b68442192465ce5e66e1f3c4500ea6009f Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sat, 1 Feb 2025 17:47:31 +0500 Subject: [PATCH 10/60] Added NativeAOT build task. --- .../build/ExcelDna.AddIn.NativeAOT.props | 7 ++ .../build/ExcelDna.AddIn.NativeAOT.targets | 39 +++++++++++ .../ExcelDna.AddIn.Tasks.csproj | 8 +++ .../PackExcelAddInNativeAOT.cs | 69 +++++++++++++++++++ .../Properties/ExcelDna.AddIn.Tasks.targets | 33 +++++++++ .../ExcelDna.PackedResources/ExcelDnaPack.cs | 12 ++++ .../ResourceHelper.cs | 1 + Source/ExcelDna.sln | 2 + ...ddIn.Tasks.IntegrationTests.TestTarget.sln | 6 ++ 9 files changed, 177 insertions(+) create mode 100644 Package/ExcelDna.AddIn.NativeAOT/build/ExcelDna.AddIn.NativeAOT.props create mode 100644 Package/ExcelDna.AddIn.NativeAOT/build/ExcelDna.AddIn.NativeAOT.targets create mode 100644 Source/ExcelDna.AddIn.Tasks/PackExcelAddInNativeAOT.cs diff --git a/Package/ExcelDna.AddIn.NativeAOT/build/ExcelDna.AddIn.NativeAOT.props b/Package/ExcelDna.AddIn.NativeAOT/build/ExcelDna.AddIn.NativeAOT.props new file mode 100644 index 00000000..facba43b --- /dev/null +++ b/Package/ExcelDna.AddIn.NativeAOT/build/ExcelDna.AddIn.NativeAOT.props @@ -0,0 +1,7 @@ + + + true + true + true + + diff --git a/Package/ExcelDna.AddIn.NativeAOT/build/ExcelDna.AddIn.NativeAOT.targets b/Package/ExcelDna.AddIn.NativeAOT/build/ExcelDna.AddIn.NativeAOT.targets new file mode 100644 index 00000000..0bb91067 --- /dev/null +++ b/Package/ExcelDna.AddIn.NativeAOT/build/ExcelDna.AddIn.NativeAOT.targets @@ -0,0 +1,39 @@ + + + + + $(MSBuildThisFileDirectory)..\tools\ + + + + $(ExcelDnaToolsPath)net6.0-windows7.0\ + + + $(ExcelDnaToolsPath)net462\ + + + + + + + true + + + + + + + + + + diff --git a/Source/ExcelDna.AddIn.Tasks/ExcelDna.AddIn.Tasks.csproj b/Source/ExcelDna.AddIn.Tasks/ExcelDna.AddIn.Tasks.csproj index 50aeb31e..e46dc89a 100644 --- a/Source/ExcelDna.AddIn.Tasks/ExcelDna.AddIn.Tasks.csproj +++ b/Source/ExcelDna.AddIn.Tasks/ExcelDna.AddIn.Tasks.csproj @@ -62,6 +62,14 @@ ExcelDna.AddIn.props Designer + + ExcelDna.AddIn.NativeAOT.targets + Designer + + + ExcelDna.AddIn.NativeAOT.props + Designer + diff --git a/Source/ExcelDna.AddIn.Tasks/PackExcelAddInNativeAOT.cs b/Source/ExcelDna.AddIn.Tasks/PackExcelAddInNativeAOT.cs new file mode 100644 index 00000000..a6d21c9a --- /dev/null +++ b/Source/ExcelDna.AddIn.Tasks/PackExcelAddInNativeAOT.cs @@ -0,0 +1,69 @@ +using System; +using Microsoft.Build.Framework; +using ExcelDna.AddIn.Tasks.Logging; +using ExcelDna.AddIn.Tasks.Utils; +using ExcelDna.PackedResources.Logging; +using System.IO; + +namespace ExcelDna.AddIn.Tasks +{ + public class PackExcelAddInNativeAOT : AbstractTask + { + private readonly IBuildLogger _log; + private readonly IExcelDnaFileSystem _fileSystem; + + public PackExcelAddInNativeAOT() + { + _log = new BuildLogger(this, "PackExcelAddInNativeAOT"); + _fileSystem = new ExcelDnaPhysicalFileSystem(); + } + + internal PackExcelAddInNativeAOT(IBuildLogger log, IExcelDnaFileSystem fileSystem) + { + _log = log ?? throw new ArgumentNullException(nameof(log)); + _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); + } + + public override bool Execute() + { + try + { + _log.Debug("Running PackExcelAddInNativeAOT Task"); + + bool useManagedResourceResolver = false; +#if NETCOREAPP + useManagedResourceResolver = PackManagedOnWindows || !OperatingSystem.IsWindows(); +#endif + + int result = ExcelDna.PackedResources.ExcelDnaPack.PackNativeAOT(OutputPackedXllFileName, RunMultithreaded, useManagedResourceResolver, _log); + if (result != 0) + throw new ApplicationException($"Pack failed with exit code {result}."); + + return true; + } + catch (Exception ex) + { + _log.Error(ex, ex.Message); + _log.Error(ex, ex.ToString()); + return false; + } + } + + /// + /// Output path + /// + [Required] + public string OutputPackedXllFileName { get; set; } + + /// + /// Use multi threading + /// + [Required] + public bool RunMultithreaded { get; set; } + + /// + /// Enable/disable cross-platform resource packing implementation when executing on Windows. + /// + public bool PackManagedOnWindows { get; set; } + } +} diff --git a/Source/ExcelDna.AddIn.Tasks/Properties/ExcelDna.AddIn.Tasks.targets b/Source/ExcelDna.AddIn.Tasks/Properties/ExcelDna.AddIn.Tasks.targets index 2a58df8e..595031ce 100644 --- a/Source/ExcelDna.AddIn.Tasks/Properties/ExcelDna.AddIn.Tasks.targets +++ b/Source/ExcelDna.AddIn.Tasks/Properties/ExcelDna.AddIn.Tasks.targets @@ -22,6 +22,7 @@ + + + + + + + + + filesToPublish, bool packManagedDependencies, string[] dependenciesToExcludeParam, string outputBitness, IBuildLogger buildLogger) { List dependenciesToExclude = new List(); diff --git a/Source/ExcelDna.PackedResources/ResourceHelper.cs b/Source/ExcelDna.PackedResources/ResourceHelper.cs index 864b8ac5..b091eeb0 100644 --- a/Source/ExcelDna.PackedResources/ResourceHelper.cs +++ b/Source/ExcelDna.PackedResources/ResourceHelper.cs @@ -26,6 +26,7 @@ internal enum TypeName PDB = 4, NATIVE_LIBRARY = 5, DOC = 6, + NATIVE_ASSEMBLY = 7, } // TODO: Learn about locales diff --git a/Source/ExcelDna.sln b/Source/ExcelDna.sln index b310909c..c20d759d 100644 --- a/Source/ExcelDna.sln +++ b/Source/ExcelDna.sln @@ -24,6 +24,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExcelDna.AddIn.Tasks", "Exc ProjectSection(ProjectDependencies) = postProject {A8D668E2-63C1-4F4E-A01E-E026C6E4D601} = {A8D668E2-63C1-4F4E-A01E-E026C6E4D601} {A9887347-3E93-4E4E-96DF-227648E57B60} = {A9887347-3E93-4E4E-96DF-227648E57B60} + {D50C3A8E-46F1-F61B-C8F5-ECDA05995EEB} = {D50C3A8E-46F1-F61B-C8F5-ECDA05995EEB} + {DAF494B7-16F3-AAA7-5F71-234663023BB6} = {DAF494B7-16F3-AAA7-5F71-234663023BB6} {FD7F2EE3-9922-4825-96A2-BE2C877BAEB9} = {FD7F2EE3-9922-4825-96A2-BE2C877BAEB9} EndProjectSection EndProject diff --git a/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget.sln b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget.sln index 16df8460..e1e08d8b 100644 --- a/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget.sln +++ b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget.sln @@ -130,6 +130,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SDKPackDoc", "SDKPackDoc\SD EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NET8RuntimeFrameworkVersion", "NET8RuntimeFrameworkVersion\NET8RuntimeFrameworkVersion.csproj", "{0A160CF6-061A-40C7-9F30-F6D7352F6178}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AOTMinimal", "AOTMinimal\AOTMinimal.csproj", "{02FE8D18-36B0-47F3-AF76-00D05BC48332}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -388,6 +390,10 @@ Global {0A160CF6-061A-40C7-9F30-F6D7352F6178}.Debug|Any CPU.Build.0 = Debug|Any CPU {0A160CF6-061A-40C7-9F30-F6D7352F6178}.Release|Any CPU.ActiveCfg = Release|Any CPU {0A160CF6-061A-40C7-9F30-F6D7352F6178}.Release|Any CPU.Build.0 = Release|Any CPU + {02FE8D18-36B0-47F3-AF76-00D05BC48332}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {02FE8D18-36B0-47F3-AF76-00D05BC48332}.Debug|Any CPU.Build.0 = Debug|Any CPU + {02FE8D18-36B0-47F3-AF76-00D05BC48332}.Release|Any CPU.ActiveCfg = Release|Any CPU + {02FE8D18-36B0-47F3-AF76-00D05BC48332}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From c89ff506cd2be3ad293a666945dc57c91ab4e098 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sat, 1 Feb 2025 17:50:07 +0500 Subject: [PATCH 11/60] Added AOTMinimal TestTarget project. --- .../AOTMinimal/AOTMinimal.csproj | 31 +++++++++++++++++++ .../AOTMinimal/Functions.cs | 19 ++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/AOTMinimal/AOTMinimal.csproj create mode 100644 Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/AOTMinimal/Functions.cs diff --git a/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/AOTMinimal/AOTMinimal.csproj b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/AOTMinimal/AOTMinimal.csproj new file mode 100644 index 00000000..3f887ece --- /dev/null +++ b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/AOTMinimal/AOTMinimal.csproj @@ -0,0 +1,31 @@ + + + + net8.0-windows + enable + enable + + win-x64 + true + + + + + ..\..\.exceldna.addin\tools\net6.0-windows7.0\ExcelDna.Integration.dll + + + ..\..\.exceldna.addin\tools\net6.0-windows7.0\ExcelDna.ManagedHost.dll + + + ..\..\.exceldna.addin\tools\net6.0-windows7.0\ExcelDna.Loader.dll + + + + + + + + + + + diff --git a/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/AOTMinimal/Functions.cs b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/AOTMinimal/Functions.cs new file mode 100644 index 00000000..b9b5dff9 --- /dev/null +++ b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/AOTMinimal/Functions.cs @@ -0,0 +1,19 @@ +using ExcelDna.Integration; + +namespace AOTMinimal +{ + public class Functions + { + [ExcelFunction] + public static string MyHello(string name) + { + return $"Hello {name}!"; + } + + [ExcelFunction] + public static int MySum(int i1, int i2) + { + return i1 + i2; + } + } +} From 66724a64e876486b13289dc3f3e4fc585e8e1cf8 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sat, 1 Feb 2025 21:19:27 +0500 Subject: [PATCH 12/60] Added building ExcelDna.AddIn.NativeAOT package. --- Build/BuildPackages.bat | 7 +-- Build/build.bat | 9 ++++ MasterBuild/MasterBuild.cmd | 3 +- .../ExcelDna.AddIn.NativeAOT.nuspec | 54 +++++++++++++++++++ Package/package.cmd | 4 ++ 5 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 Package/ExcelDna.AddIn.NativeAOT/ExcelDna.AddIn.NativeAOT.nuspec diff --git a/Build/BuildPackages.bat b/Build/BuildPackages.bat index 5e4d4dfa..e6d06f84 100644 --- a/Build/BuildPackages.bat +++ b/Build/BuildPackages.bat @@ -1,8 +1,9 @@ setlocal set PackageVersion=%1 -set DllVersion=%2 -set MSBuildPath=%3 +set PackageNativeAOTVersion=%2 +set DllVersion=%3 +set MSBuildPath=%4 set rcfile=..\Source\versioninfo.rc2 PowerShell "(Get-Content %rcfile%) -replace '\d+,\d+,\d+,\d+', '%DllVersion%'.Replace('.',',') -replace '\d+\.\d+\.\d+\.\d+', '%DllVersion%' | Set-Content %rcfile%" @@ -18,7 +19,7 @@ call build.bat @if errorlevel 1 goto end cd ..\Package -call package.cmd %PackageVersion% +call package.cmd %PackageVersion% %PackageNativeAOTVersion% @if errorlevel 1 goto end set pushfile=push.cmd diff --git a/Build/build.bat b/Build/build.bat index ae140b5f..21721d26 100644 --- a/Build/build.bat +++ b/Build/build.bat @@ -21,6 +21,9 @@ copy /Y ..\Source\ExcelDnaPack\bin\Release\net6.0-windows\ExcelDnaPack.runtimeco if not exist "..\Package\ExcelDna.AddIn\tools\net462\" mkdir "..\Package\ExcelDna.AddIn\tools\net462\" if not exist "..\Package\ExcelDna.AddIn\tools\net6.0-windows\" mkdir "..\Package\ExcelDna.AddIn\tools\net6.0-windows\" +if not exist "..\Package\ExcelDna.AddIn.NativeAOT\tools\" mkdir "..\Package\ExcelDna.AddIn.NativeAOT\tools\" +if not exist "..\Package\ExcelDna.AddIn.NativeAOT\lib\net6.0-windows\" mkdir "..\Package\ExcelDna.AddIn.NativeAOT\lib\net6.0-windows\" +if not exist "..\Package\ExcelDna.AddIn.NativeAOT\analyzers\dotnet\cs" mkdir "..\Package\ExcelDna.AddIn.NativeAOT\analyzers\dotnet\cs" copy /Y ..\Source\ExcelDna.AddIn.Tasks\bin\Release\net462\ExcelDna.AddIn.Tasks.dll ..\Package\ExcelDna.AddIn\tools\net462\ copy /Y ..\Source\ExcelDna.AddIn.Tasks\bin\Release\net462\ExcelDna.AddIn.Tasks.pdb ..\Package\ExcelDna.AddIn\tools\net462\ @@ -31,5 +34,11 @@ copy /Y ..\Source\ExcelDna.AddIn.Tasks\bin\Release\net462\System.Collections.Imm copy /Y ..\Source\ExcelDna.AddIn.Tasks\bin\Release\net6.0-windows\ExcelDna.AddIn.Tasks.dll ..\Package\ExcelDna.AddIn\tools\net6.0-windows\ copy /Y ..\Source\ExcelDna.AddIn.Tasks\bin\Release\net6.0-windows\ExcelDna.AddIn.Tasks.pdb ..\Package\ExcelDna.AddIn\tools\net6.0-windows\ +copy /Y "..\Source\ExcelDna.Integration\bin\Release\net6.0-windows\ExcelDna.Integration.dll" "..\Package\ExcelDna.AddIn.NativeAOT\lib\net6.0-windows\" +copy /Y "..\Source\ExcelDna.ManagedHost\bin\Release\net6.0-windows\ExcelDna.ManagedHost.dll" "..\Package\ExcelDna.AddIn.NativeAOT\lib\net6.0-windows\" +copy /Y "..\Source\ExcelDna.Loader\bin\Release\net6.0-windows\ExcelDna.Loader.dll" "..\Package\ExcelDna.AddIn.NativeAOT\lib\net6.0-windows\" +copy /Y "..\Source\ExcelDna.SourceGenerator.NativeAOT\bin\Release\netstandard2.0\ExcelDna.SourceGenerator.NativeAOT.dll" "..\Package\ExcelDna.AddIn.NativeAOT\analyzers\dotnet\cs\" +copy /Y "..\Source\ExcelDna.Host.NativeAOT\bin\Release\x64\ExcelDna.Host.NativeAOT.x64.xll" "..\Package\ExcelDna.AddIn.NativeAOT\tools\ExcelDnaNativeAOT64.xll" + copy /Y ..\Distribution\net462\ ..\Distribution\ diff --git a/MasterBuild/MasterBuild.cmd b/MasterBuild/MasterBuild.cmd index 82543501..06286747 100644 --- a/MasterBuild/MasterBuild.cmd +++ b/MasterBuild/MasterBuild.cmd @@ -1,6 +1,7 @@ setlocal set PackageVersion=1.9.0-alpha3 +set PackageNativeAOTVersion=0.1.0 set PackageReferenceVersion=1.9.0-alpha3 set DllVersion=1.9.0.3 @@ -24,7 +25,7 @@ PowerShell "(Get-Content %targetsfile%) -replace '_VERSION_', '%PackageReference @if errorlevel 1 goto end cd %rootPath%\ExcelDna\Build -call BuildPackages.bat %PackageVersion% %DllVersion% %MSBuildPath% +call BuildPackages.bat %PackageVersion% %PackageNativeAOTVersion% %DllVersion% %MSBuildPath% @if errorlevel 1 goto end cd %rootPath%\Registration\Build diff --git a/Package/ExcelDna.AddIn.NativeAOT/ExcelDna.AddIn.NativeAOT.nuspec b/Package/ExcelDna.AddIn.NativeAOT/ExcelDna.AddIn.NativeAOT.nuspec new file mode 100644 index 00000000..cc05ab36 --- /dev/null +++ b/Package/ExcelDna.AddIn.NativeAOT/ExcelDna.AddIn.NativeAOT.nuspec @@ -0,0 +1,54 @@ + + + + ExcelDna.AddIn.NativeAOT + $ExcelDnaNativeAOTVersion$ + Excel-DNA Add-In NativeAOT + Govert van Drimmelen + Govert van Drimmelen + http://excel-dna.net + + images\ExcelDna-nu.png + Zlib + false + + Excel-DNA eases the development of Excel add-ins using .NET. + Add-ins created with Excel-DNA can export high-performance user-defined functions and macros, and can be packed into a single file for easy distribution and installation. + + Excel versions 2007 through 2021 / Office 365 can be targeted with a single add-in. + Advanced Excel features are supported, including multi-threaded recalculation, registration-free RTD servers and customized Ribbon and Task Pane interfaces and asynchronous functions. + + Excel-DNA supports .NET Framework version 4.6.2 to 4.8.1, and .NET 6.0+ + + The Excel-DNA Runtime is free for all use, and distributed under a permissive open-source license that also allows commercial use. + Excel-DNA is an independent project to integrate .NET into Excel. + excel exceldna udf excel-dna + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Package/package.cmd b/Package/package.cmd index ce901299..be9160ec 100644 --- a/Package/package.cmd +++ b/Package/package.cmd @@ -5,6 +5,7 @@ set currentPath=%~dp0 set basePath=%currentPath:~0,-1% set outputPath=%basePath%\nupkg set ExcelDnaVersion=%1 +set ExcelDnaNativeAOTVersion=%2 if exist "%outputPath%\*.nupkg" del "%outputPath%\*.nupkg" @@ -18,6 +19,9 @@ nuget.exe pack "%basePath%\ExcelDna.Templates\ExcelDna.Templates.nuspec" -BasePa nuget.exe pack "%basePath%\ExcelDna.AddIn\ExcelDna.AddIn.nuspec" -BasePath "%basePath%\ExcelDna.AddIn" -OutputDirectory "%outputPath%" -Verbosity detailed -NonInteractive -Prop ExcelDnaVersion="%ExcelDnaVersion%" @if errorlevel 1 goto end +nuget.exe pack "%basePath%\ExcelDna.AddIn.NativeAOT\ExcelDna.AddIn.NativeAOT.nuspec" -BasePath "%basePath%\ExcelDna.AddIn.NativeAOT" -OutputDirectory "%outputPath%" -Verbosity detailed -NonInteractive -Prop ExcelDnaNativeAOTVersion="%ExcelDnaNativeAOTVersion%" +@if errorlevel 1 goto end + nuget.exe pack "%basePath%\ExcelDna.Integration\ExcelDna.Integration.nuspec" -BasePath "%basePath%\ExcelDna.Integration" -OutputDirectory "%outputPath%" -Verbosity detailed -NonInteractive -Prop ExcelDnaVersion="%ExcelDnaVersion%" -Symbols -SymbolPackageFormat snupkg @if errorlevel 1 goto end From 049566514515c1b515875b380bd23a6c675b3199 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sat, 1 Feb 2025 21:56:27 +0500 Subject: [PATCH 13/60] Disabled release AddIn.RuntimeTests builds. --- Source/ExcelDna.sln | 3 --- 1 file changed, 3 deletions(-) diff --git a/Source/ExcelDna.sln b/Source/ExcelDna.sln index c20d759d..304956e4 100644 --- a/Source/ExcelDna.sln +++ b/Source/ExcelDna.sln @@ -245,7 +245,6 @@ Global {297D72F7-FD48-4751-B2EF-F97DBAD0C901}.Debug|x64.Build.0 = Debug|Any CPU {297D72F7-FD48-4751-B2EF-F97DBAD0C901}.Release|Win32.ActiveCfg = Release|Any CPU {297D72F7-FD48-4751-B2EF-F97DBAD0C901}.Release|x64.ActiveCfg = Release|Any CPU - {297D72F7-FD48-4751-B2EF-F97DBAD0C901}.Release|x64.Build.0 = Release|Any CPU {238F95C5-87DF-4973-88C2-5A9509C3935F}.Debug|Win32.ActiveCfg = Debug|Any CPU {238F95C5-87DF-4973-88C2-5A9509C3935F}.Debug|Win32.Build.0 = Debug|Any CPU {238F95C5-87DF-4973-88C2-5A9509C3935F}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -315,9 +314,7 @@ Global {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Debug|x64.ActiveCfg = Debug|Any CPU {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Debug|x64.Build.0 = Debug|Any CPU {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Release|Win32.ActiveCfg = Release|Any CPU - {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Release|Win32.Build.0 = Release|Any CPU {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Release|x64.ActiveCfg = Release|Any CPU - {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 724fbfa567797c7c45d62c1f9890a65bf616bdf1 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sat, 15 Feb 2025 17:01:14 +0500 Subject: [PATCH 14/60] Disabled runtime tests in Debug|Win32 configuration. --- Source/ExcelDna.sln | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Source/ExcelDna.sln b/Source/ExcelDna.sln index 304956e4..0a896b71 100644 --- a/Source/ExcelDna.sln +++ b/Source/ExcelDna.sln @@ -254,7 +254,6 @@ Global {238F95C5-87DF-4973-88C2-5A9509C3935F}.Release|x64.ActiveCfg = Release|Any CPU {238F95C5-87DF-4973-88C2-5A9509C3935F}.Release|x64.Build.0 = Release|Any CPU {8D04B68B-1EFE-48DC-A0B5-D7ACC293694B}.Debug|Win32.ActiveCfg = Debug|Any CPU - {8D04B68B-1EFE-48DC-A0B5-D7ACC293694B}.Debug|Win32.Build.0 = Debug|Any CPU {8D04B68B-1EFE-48DC-A0B5-D7ACC293694B}.Debug|x64.ActiveCfg = Debug|Any CPU {8D04B68B-1EFE-48DC-A0B5-D7ACC293694B}.Debug|x64.Build.0 = Debug|Any CPU {8D04B68B-1EFE-48DC-A0B5-D7ACC293694B}.Release|Win32.ActiveCfg = Release|Any CPU @@ -262,7 +261,6 @@ Global {8D04B68B-1EFE-48DC-A0B5-D7ACC293694B}.Release|x64.ActiveCfg = Release|Any CPU {8D04B68B-1EFE-48DC-A0B5-D7ACC293694B}.Release|x64.Build.0 = Release|Any CPU {55AEB960-2857-323E-3E82-5A8AA5913A18}.Debug|Win32.ActiveCfg = Debug|Any CPU - {55AEB960-2857-323E-3E82-5A8AA5913A18}.Debug|Win32.Build.0 = Debug|Any CPU {55AEB960-2857-323E-3E82-5A8AA5913A18}.Debug|x64.ActiveCfg = Debug|Any CPU {55AEB960-2857-323E-3E82-5A8AA5913A18}.Debug|x64.Build.0 = Debug|Any CPU {55AEB960-2857-323E-3E82-5A8AA5913A18}.Release|Win32.ActiveCfg = Release|Any CPU @@ -270,7 +268,6 @@ Global {55AEB960-2857-323E-3E82-5A8AA5913A18}.Release|x64.ActiveCfg = Release|Any CPU {55AEB960-2857-323E-3E82-5A8AA5913A18}.Release|x64.Build.0 = Release|Any CPU {2F5539CC-E302-49B6-88A9-9264DC6413B3}.Debug|Win32.ActiveCfg = Debug|Any CPU - {2F5539CC-E302-49B6-88A9-9264DC6413B3}.Debug|Win32.Build.0 = Debug|Any CPU {2F5539CC-E302-49B6-88A9-9264DC6413B3}.Debug|x64.ActiveCfg = Debug|Any CPU {2F5539CC-E302-49B6-88A9-9264DC6413B3}.Debug|x64.Build.0 = Debug|Any CPU {2F5539CC-E302-49B6-88A9-9264DC6413B3}.Release|Win32.ActiveCfg = Release|Any CPU @@ -278,7 +275,6 @@ Global {2F5539CC-E302-49B6-88A9-9264DC6413B3}.Release|x64.ActiveCfg = Release|Any CPU {2F5539CC-E302-49B6-88A9-9264DC6413B3}.Release|x64.Build.0 = Release|Any CPU {7CA501E1-FB74-4903-B34D-EFE513C5B428}.Debug|Win32.ActiveCfg = Debug|Any CPU - {7CA501E1-FB74-4903-B34D-EFE513C5B428}.Debug|Win32.Build.0 = Debug|Any CPU {7CA501E1-FB74-4903-B34D-EFE513C5B428}.Debug|x64.ActiveCfg = Debug|Any CPU {7CA501E1-FB74-4903-B34D-EFE513C5B428}.Debug|x64.Build.0 = Debug|Any CPU {7CA501E1-FB74-4903-B34D-EFE513C5B428}.Release|Win32.ActiveCfg = Release|Any CPU @@ -310,7 +306,6 @@ Global {DAF494B7-16F3-AAA7-5F71-234663023BB6}.Release|x64.ActiveCfg = Release|Any CPU {DAF494B7-16F3-AAA7-5F71-234663023BB6}.Release|x64.Build.0 = Release|Any CPU {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Debug|Win32.ActiveCfg = Debug|Any CPU - {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Debug|Win32.Build.0 = Debug|Any CPU {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Debug|x64.ActiveCfg = Debug|Any CPU {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Debug|x64.Build.0 = Debug|Any CPU {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Release|Win32.ActiveCfg = Release|Any CPU From b51cadaff3242609a44f9eabf0805c4f1416fe26 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sat, 15 Feb 2025 17:27:24 +0500 Subject: [PATCH 15/60] Disabled runtime tests in Release|Win32 configuration. --- Source/ExcelDna.sln | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Source/ExcelDna.sln b/Source/ExcelDna.sln index 0a896b71..028f247f 100644 --- a/Source/ExcelDna.sln +++ b/Source/ExcelDna.sln @@ -203,11 +203,9 @@ Global {C9CAD3E4-E6F1-4BD2-AF89-57950AB15388}.Release|x64.ActiveCfg = Release|Any CPU {C9CAD3E4-E6F1-4BD2-AF89-57950AB15388}.Release|x64.Build.0 = Release|Any CPU {3AFD9408-48AC-43B4-8E55-4E7D73168FEA}.Debug|Win32.ActiveCfg = Debug|Any CPU - {3AFD9408-48AC-43B4-8E55-4E7D73168FEA}.Debug|Win32.Build.0 = Debug|Any CPU {3AFD9408-48AC-43B4-8E55-4E7D73168FEA}.Debug|x64.ActiveCfg = Debug|Any CPU {3AFD9408-48AC-43B4-8E55-4E7D73168FEA}.Debug|x64.Build.0 = Debug|Any CPU {3AFD9408-48AC-43B4-8E55-4E7D73168FEA}.Release|Win32.ActiveCfg = Release|Any CPU - {3AFD9408-48AC-43B4-8E55-4E7D73168FEA}.Release|Win32.Build.0 = Release|Any CPU {3AFD9408-48AC-43B4-8E55-4E7D73168FEA}.Release|x64.ActiveCfg = Release|Any CPU {3AFD9408-48AC-43B4-8E55-4E7D73168FEA}.Release|x64.Build.0 = Release|Any CPU {DC10CEC8-C6CE-4148-838F-C3DD4EA2A2A3}.Debug|Win32.ActiveCfg = Debug|Any CPU @@ -257,28 +255,24 @@ Global {8D04B68B-1EFE-48DC-A0B5-D7ACC293694B}.Debug|x64.ActiveCfg = Debug|Any CPU {8D04B68B-1EFE-48DC-A0B5-D7ACC293694B}.Debug|x64.Build.0 = Debug|Any CPU {8D04B68B-1EFE-48DC-A0B5-D7ACC293694B}.Release|Win32.ActiveCfg = Release|Any CPU - {8D04B68B-1EFE-48DC-A0B5-D7ACC293694B}.Release|Win32.Build.0 = Release|Any CPU {8D04B68B-1EFE-48DC-A0B5-D7ACC293694B}.Release|x64.ActiveCfg = Release|Any CPU {8D04B68B-1EFE-48DC-A0B5-D7ACC293694B}.Release|x64.Build.0 = Release|Any CPU {55AEB960-2857-323E-3E82-5A8AA5913A18}.Debug|Win32.ActiveCfg = Debug|Any CPU {55AEB960-2857-323E-3E82-5A8AA5913A18}.Debug|x64.ActiveCfg = Debug|Any CPU {55AEB960-2857-323E-3E82-5A8AA5913A18}.Debug|x64.Build.0 = Debug|Any CPU {55AEB960-2857-323E-3E82-5A8AA5913A18}.Release|Win32.ActiveCfg = Release|Any CPU - {55AEB960-2857-323E-3E82-5A8AA5913A18}.Release|Win32.Build.0 = Release|Any CPU {55AEB960-2857-323E-3E82-5A8AA5913A18}.Release|x64.ActiveCfg = Release|Any CPU {55AEB960-2857-323E-3E82-5A8AA5913A18}.Release|x64.Build.0 = Release|Any CPU {2F5539CC-E302-49B6-88A9-9264DC6413B3}.Debug|Win32.ActiveCfg = Debug|Any CPU {2F5539CC-E302-49B6-88A9-9264DC6413B3}.Debug|x64.ActiveCfg = Debug|Any CPU {2F5539CC-E302-49B6-88A9-9264DC6413B3}.Debug|x64.Build.0 = Debug|Any CPU {2F5539CC-E302-49B6-88A9-9264DC6413B3}.Release|Win32.ActiveCfg = Release|Any CPU - {2F5539CC-E302-49B6-88A9-9264DC6413B3}.Release|Win32.Build.0 = Release|Any CPU {2F5539CC-E302-49B6-88A9-9264DC6413B3}.Release|x64.ActiveCfg = Release|Any CPU {2F5539CC-E302-49B6-88A9-9264DC6413B3}.Release|x64.Build.0 = Release|Any CPU {7CA501E1-FB74-4903-B34D-EFE513C5B428}.Debug|Win32.ActiveCfg = Debug|Any CPU {7CA501E1-FB74-4903-B34D-EFE513C5B428}.Debug|x64.ActiveCfg = Debug|Any CPU {7CA501E1-FB74-4903-B34D-EFE513C5B428}.Debug|x64.Build.0 = Debug|Any CPU {7CA501E1-FB74-4903-B34D-EFE513C5B428}.Release|Win32.ActiveCfg = Release|Any CPU - {7CA501E1-FB74-4903-B34D-EFE513C5B428}.Release|Win32.Build.0 = Release|Any CPU {7CA501E1-FB74-4903-B34D-EFE513C5B428}.Release|x64.ActiveCfg = Release|Any CPU {7CA501E1-FB74-4903-B34D-EFE513C5B428}.Release|x64.Build.0 = Release|Any CPU {151AE960-6320-402D-BDD0-D76DF96F2BD7}.Debug|Win32.ActiveCfg = Debug|Any CPU From 351aaaabca3b6a2150ff0ed24a3241bf7a28cbfc Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sat, 15 Feb 2025 18:48:36 +0500 Subject: [PATCH 16/60] Added support for Release configuration to runtime tests. --- Source/ExcelDna.sln | 2 + .../Tests/ExcelDna.RuntimeTests/AddInPath.cs | 19 +++++++ .../Tests/ExcelDna.RuntimeTests/NativeAOT.cs | 6 +- .../ObjectHandleOutOfProcess.cs | 12 ++-- .../ExcelDna.RuntimeTests/Registration.cs | 56 +++++++++---------- .../RegistrationOutOfProcess.cs | 4 +- .../RegistrationSample.cs | 22 ++++---- .../RegistrationSampleFS.cs | 4 +- .../RegistrationSampleOutOfProcess.cs | 6 +- .../RegistrationSampleOutOfProcessFS.cs | 6 +- .../RegistrationSampleVB.cs | 8 +-- .../UserCodeConversions.cs | 4 +- 12 files changed, 75 insertions(+), 74 deletions(-) create mode 100644 Source/Tests/ExcelDna.RuntimeTests/AddInPath.cs diff --git a/Source/ExcelDna.sln b/Source/ExcelDna.sln index 028f247f..2231987f 100644 --- a/Source/ExcelDna.sln +++ b/Source/ExcelDna.sln @@ -243,6 +243,7 @@ Global {297D72F7-FD48-4751-B2EF-F97DBAD0C901}.Debug|x64.Build.0 = Debug|Any CPU {297D72F7-FD48-4751-B2EF-F97DBAD0C901}.Release|Win32.ActiveCfg = Release|Any CPU {297D72F7-FD48-4751-B2EF-F97DBAD0C901}.Release|x64.ActiveCfg = Release|Any CPU + {297D72F7-FD48-4751-B2EF-F97DBAD0C901}.Release|x64.Build.0 = Release|Any CPU {238F95C5-87DF-4973-88C2-5A9509C3935F}.Debug|Win32.ActiveCfg = Debug|Any CPU {238F95C5-87DF-4973-88C2-5A9509C3935F}.Debug|Win32.Build.0 = Debug|Any CPU {238F95C5-87DF-4973-88C2-5A9509C3935F}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -304,6 +305,7 @@ Global {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Debug|x64.Build.0 = Debug|Any CPU {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Release|Win32.ActiveCfg = Release|Any CPU {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Release|x64.ActiveCfg = Release|Any CPU + {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Source/Tests/ExcelDna.RuntimeTests/AddInPath.cs b/Source/Tests/ExcelDna.RuntimeTests/AddInPath.cs new file mode 100644 index 00000000..f2112a5e --- /dev/null +++ b/Source/Tests/ExcelDna.RuntimeTests/AddInPath.cs @@ -0,0 +1,19 @@ +namespace ExcelDna.RuntimeTests +{ + internal class AddInPath + { +#if DEBUG + public const string RuntimeTestsAOT = @"..\..\..\..\ExcelDna.AddIn.RuntimeTestsAOT\bin\Debug\net8.0-windows\win-x64\publish\ExcelDna.AddIn.RuntimeTestsAOT"; + public const string RuntimeTests = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn"; + public const string RegistrationSample = @"..\..\..\..\ExcelDna.AddIn.RegistrationSample\bin\Debug\net6.0-windows\ExcelDna.AddIn.RegistrationSample-AddIn"; + public const string RegistrationSampleFS = @"..\..\..\..\ExcelDna.AddIn.RegistrationSampleFS\bin\Debug\net6.0-windows\ExcelDna.AddIn.RegistrationSampleFS-AddIn"; + public const string RegistrationSampleVB = @"..\..\..\..\ExcelDna.AddIn.RegistrationSampleVB\bin\Debug\net6.0-windows\ExcelDna.AddIn.RegistrationSampleVB-AddIn"; +#else + public const string RuntimeTestsAOT = @"..\..\..\..\ExcelDna.AddIn.RuntimeTestsAOT\bin\Release\net8.0-windows\win-x64\publish\ExcelDna.AddIn.RuntimeTestsAOT"; + public const string RuntimeTests = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Release\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn"; + public const string RegistrationSample = @"..\..\..\..\ExcelDna.AddIn.RegistrationSample\bin\Release\net6.0-windows\ExcelDna.AddIn.RegistrationSample-AddIn"; + public const string RegistrationSampleFS = @"..\..\..\..\ExcelDna.AddIn.RegistrationSampleFS\bin\Release\net6.0-windows\ExcelDna.AddIn.RegistrationSampleFS-AddIn"; + public const string RegistrationSampleVB = @"..\..\..\..\ExcelDna.AddIn.RegistrationSampleVB\bin\Release\net6.0-windows\ExcelDna.AddIn.RegistrationSampleVB-AddIn"; +#endif + } +} diff --git a/Source/Tests/ExcelDna.RuntimeTests/NativeAOT.cs b/Source/Tests/ExcelDna.RuntimeTests/NativeAOT.cs index 3196214f..0d949d6d 100644 --- a/Source/Tests/ExcelDna.RuntimeTests/NativeAOT.cs +++ b/Source/Tests/ExcelDna.RuntimeTests/NativeAOT.cs @@ -3,10 +3,9 @@ namespace ExcelDna.RuntimeTests { -#if DEBUG public class NativeAOT { - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTestsAOT\bin\Debug\net8.0-windows\win-x64\publish\ExcelDna.AddIn.RuntimeTestsAOT")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTestsAOT)] public void Hello() { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1:B1"]; @@ -14,7 +13,7 @@ public void Hello() Assert.Equal("Hello world!", functionRange.Value.ToString()); } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTestsAOT\bin\Debug\net8.0-windows\win-x64\publish\ExcelDna.AddIn.RuntimeTestsAOT")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTestsAOT)] public void Sum() { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1:B1"]; @@ -22,5 +21,4 @@ public void Sum() Assert.Equal("7", functionRange.Value.ToString()); } } -#endif } diff --git a/Source/Tests/ExcelDna.RuntimeTests/ObjectHandleOutOfProcess.cs b/Source/Tests/ExcelDna.RuntimeTests/ObjectHandleOutOfProcess.cs index 8b9be861..8c3a8c8d 100644 --- a/Source/Tests/ExcelDna.RuntimeTests/ObjectHandleOutOfProcess.cs +++ b/Source/Tests/ExcelDna.RuntimeTests/ObjectHandleOutOfProcess.cs @@ -4,12 +4,11 @@ namespace ExcelDna.RuntimeTests { -#if DEBUG [ExcelTestSettings(OutOfProcess = true)] [Collection("OutOfProcess")] public class ObjectHandleOutOfProcess { - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void ThreadSafe() { for (int i = 1; i <= 5; ++i) @@ -31,7 +30,7 @@ public void ThreadSafe() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void Disposable() { { @@ -75,7 +74,7 @@ public void Disposable() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void TaskObjectStableCreate() { string v1; @@ -105,7 +104,7 @@ public void TaskObjectStableCreate() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void TaskDisposable() { foreach (int delay in new[] { 0, 500 }) @@ -154,7 +153,7 @@ public void TaskDisposable() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void AsyncObjectCreate() { foreach (int delay in new[] { 0, 500 }) @@ -183,5 +182,4 @@ public void AsyncObjectCreate() } } } -#endif } diff --git a/Source/Tests/ExcelDna.RuntimeTests/Registration.cs b/Source/Tests/ExcelDna.RuntimeTests/Registration.cs index 8e6512f6..7eb5bc5b 100644 --- a/Source/Tests/ExcelDna.RuntimeTests/Registration.cs +++ b/Source/Tests/ExcelDna.RuntimeTests/Registration.cs @@ -3,10 +3,9 @@ namespace ExcelDna.RuntimeTests { -#if DEBUG public class Registration { - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void SayHello() { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1:B1"]; @@ -14,7 +13,7 @@ public void SayHello() Assert.Equal("Hello world", functionRange.Value.ToString()); } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void Double() { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1:B1"]; @@ -25,7 +24,7 @@ public void Double() Assert.Equal("0", functionRange.Value.ToString()); } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void DateTime() { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1:B1"]; @@ -33,7 +32,7 @@ public void DateTime() Assert.Equal("10/20/2024 12:00:00 AM", functionRange.Value.ToString()); } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void NullableDouble() { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1:B1"]; @@ -44,7 +43,7 @@ public void NullableDouble() Assert.Equal("Nullable VAL: NULL", functionRange.Value.ToString()); } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void NullableDateTime() { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1:B1"]; @@ -55,7 +54,7 @@ public void NullableDateTime() Assert.Equal("Nullable DateTime: NULL", functionRange.Value.ToString()); } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void OptionalDouble() { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1:B1"]; @@ -66,7 +65,7 @@ public void OptionalDouble() Assert.Equal("Optional VAL: 1.23", functionRange.Value.ToString()); } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void OptionalDateTime() { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1:B1"]; @@ -77,7 +76,7 @@ public void OptionalDateTime() Assert.Equal("Optional DateTime: 1/1/0001 12:00:00 AM", functionRange.Value.ToString()); } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void Enum() { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1:B1"]; @@ -91,7 +90,7 @@ public void Enum() Assert.Equal("Enum VAL: Utc", functionRange.Value.ToString()); } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void EnumReturn() { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1:B1"]; @@ -102,7 +101,7 @@ public void EnumReturn() Assert.Equal("Local", functionRange.Value.ToString()); } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void MapArray() { Range a1 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["A1:A1"]; @@ -127,7 +126,7 @@ public void MapArray() Assert.Equal("Array element VAL: Unspecified", b3.Value.ToString()); } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void AsyncTaskInstant() { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1:B1"]; @@ -136,7 +135,7 @@ public void AsyncTaskInstant() Assert.Equal("Hello async task world", functionRange.Value.ToString()); } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void DefaultAsyncReturnValue() { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1:B1"]; @@ -145,7 +144,7 @@ public void DefaultAsyncReturnValue() Assert.Equal(-2146826246, functionRange.Value); // #N/A } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void GettingDataAsyncReturnValue() { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1:B1"]; @@ -154,7 +153,7 @@ public void GettingDataAsyncReturnValue() Assert.Equal(-2146826245, functionRange.Value); // #GETTING_DATA } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void TaskInstant() { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1:B1"]; @@ -163,7 +162,7 @@ public void TaskInstant() Assert.Equal("Hello task world", functionRange.Value.ToString()); } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void StringArray() { Range a1 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["A1:A1"]; @@ -181,7 +180,7 @@ public void StringArray() Assert.Equal("StringArray VALS: 12.3World", functionRange.Value.ToString()); } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void StringArray2D() { Range a1 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["A1"]; @@ -208,7 +207,7 @@ public void StringArray2D() Assert.Equal("StringArray2D VALS: 15 2.36.7 HelloWorld ", functionRange.Value.ToString()); } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void UserDefinedParameterConversions() { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1:B1"]; @@ -223,7 +222,7 @@ public void UserDefinedParameterConversions() Assert.Equal("The TestType2 value is From TestType1 world2", functionRange.Value.ToString()); } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void FunctionExecutionHandlerExtended() { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1"]; @@ -233,7 +232,7 @@ public void FunctionExecutionHandlerExtended() Assert.True(functionRange.Value.ToString().Contains("MyVersion2 - OnSuccess - Result: The Version value with field count 2 is 5.4")); } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void FunctionExecutionHandlerStandard() { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1"]; @@ -243,7 +242,7 @@ public void FunctionExecutionHandlerStandard() Assert.True(functionRange.Value.ToString().Contains("SayHello - OnSuccess - Result: Hello FunctionExecutionHandlerStandard")); } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void FunctionExecutionHandlerWithAttribute() { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1"]; @@ -253,7 +252,7 @@ public void FunctionExecutionHandlerWithAttribute() Assert.True(functionRange.Value.ToString().Contains("ID=7 SayHelloWithLoggingID - OnSuccess - Result: Hello FunctionExecutionHandlerWithAttribute")); } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void Observable() { { @@ -294,7 +293,7 @@ public void Observable() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void ObjectHandles() { string b1; @@ -409,7 +408,7 @@ public void ObjectHandles() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void TaskObjectHandles() { { @@ -463,7 +462,7 @@ public void TaskObjectHandles() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void ObjectHandlesDisposable() { string b1; @@ -511,7 +510,7 @@ public void ObjectHandlesDisposable() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void TaskObjectHandlesDisposable() { string b1; @@ -570,7 +569,7 @@ public void TaskObjectHandlesDisposable() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void Range() { { @@ -590,7 +589,7 @@ public void Range() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void Params() { { @@ -610,5 +609,4 @@ public void Params() } } } -#endif } diff --git a/Source/Tests/ExcelDna.RuntimeTests/RegistrationOutOfProcess.cs b/Source/Tests/ExcelDna.RuntimeTests/RegistrationOutOfProcess.cs index 991e5c03..99e97888 100644 --- a/Source/Tests/ExcelDna.RuntimeTests/RegistrationOutOfProcess.cs +++ b/Source/Tests/ExcelDna.RuntimeTests/RegistrationOutOfProcess.cs @@ -4,12 +4,11 @@ namespace ExcelDna.RuntimeTests { -#if DEBUG [ExcelTestSettings(OutOfProcess = true)] [Collection("OutOfProcess")] public class RegistrationOutOfProcess { - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void AsyncSleep() { { @@ -30,5 +29,4 @@ public void AsyncSleep() } } } -#endif } diff --git a/Source/Tests/ExcelDna.RuntimeTests/RegistrationSample.cs b/Source/Tests/ExcelDna.RuntimeTests/RegistrationSample.cs index 6ec3a7c4..46f8e25d 100644 --- a/Source/Tests/ExcelDna.RuntimeTests/RegistrationSample.cs +++ b/Source/Tests/ExcelDna.RuntimeTests/RegistrationSample.cs @@ -3,10 +3,9 @@ namespace ExcelDna.RuntimeTests { -#if DEBUG public class RegistrationSample { - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RegistrationSample\bin\Debug\net6.0-windows\ExcelDna.AddIn.RegistrationSample-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RegistrationSample)] public void SayHello() { { @@ -21,7 +20,7 @@ public void SayHello() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RegistrationSample\bin\Debug\net6.0-windows\ExcelDna.AddIn.RegistrationSample-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RegistrationSample)] public void FunctionExecutionHandler() { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1"]; @@ -52,7 +51,7 @@ public void FunctionExecutionHandler() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RegistrationSample\bin\Debug\net6.0-windows\ExcelDna.AddIn.RegistrationSample-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RegistrationSample)] public void InstanceMemberRegistration() { { @@ -62,7 +61,7 @@ public void InstanceMemberRegistration() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RegistrationSample\bin\Debug\net6.0-windows\ExcelDna.AddIn.RegistrationSample-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RegistrationSample)] public void ParameterConversion() { { @@ -209,7 +208,7 @@ public void ParameterConversion() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RegistrationSample\bin\Debug\net6.0-windows\ExcelDna.AddIn.RegistrationSample-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RegistrationSample)] public void ParameterConversionNullableOptional() { { @@ -277,7 +276,7 @@ public void ParameterConversionNullableOptional() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RegistrationSample\bin\Debug\net6.0-windows\ExcelDna.AddIn.RegistrationSample-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RegistrationSample)] public void ParameterConversionNullable() { { @@ -327,7 +326,7 @@ public void ParameterConversionNullable() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RegistrationSample\bin\Debug\net6.0-windows\ExcelDna.AddIn.RegistrationSample-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RegistrationSample)] public void ParameterConversionEnum() { { @@ -430,7 +429,7 @@ public void ParameterConversionEnum() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RegistrationSample\bin\Debug\net6.0-windows\ExcelDna.AddIn.RegistrationSample-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RegistrationSample)] public void ParameterConversionComplex() { { @@ -502,7 +501,7 @@ public void ParameterConversionComplex() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RegistrationSample\bin\Debug\net6.0-windows\ExcelDna.AddIn.RegistrationSample-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RegistrationSample)] public void ParameterConversionType() { { @@ -522,7 +521,7 @@ public void ParameterConversionType() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RegistrationSample\bin\Debug\net6.0-windows\ExcelDna.AddIn.RegistrationSample-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RegistrationSample)] public void Params() { { @@ -542,5 +541,4 @@ public void Params() } } } -#endif } diff --git a/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleFS.cs b/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleFS.cs index eec648b2..bae08d64 100644 --- a/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleFS.cs +++ b/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleFS.cs @@ -3,10 +3,9 @@ namespace ExcelDna.RuntimeTests { -#if DEBUG public class RegistrationSampleFS { - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RegistrationSampleFS\bin\Debug\net6.0-windows\ExcelDna.AddIn.RegistrationSampleFS-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RegistrationSampleFS)] public void Optional() { { @@ -60,5 +59,4 @@ public void Optional() } } } -#endif } diff --git a/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleOutOfProcess.cs b/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleOutOfProcess.cs index e411d251..38511474 100644 --- a/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleOutOfProcess.cs +++ b/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleOutOfProcess.cs @@ -4,12 +4,11 @@ namespace ExcelDna.RuntimeTests { -#if DEBUG [ExcelTestSettings(OutOfProcess = true)] [Collection("OutOfProcess")] public class RegistrationSampleOutOfProcess { - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RegistrationSample\bin\Debug\net6.0-windows\ExcelDna.AddIn.RegistrationSample-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RegistrationSample)] public void AsyncSleep() { { @@ -30,7 +29,7 @@ public void AsyncSleep() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RegistrationSample\bin\Debug\net6.0-windows\ExcelDna.AddIn.RegistrationSample-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RegistrationSample)] public void GettingData() { { @@ -40,5 +39,4 @@ public void GettingData() } } } -#endif } diff --git a/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleOutOfProcessFS.cs b/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleOutOfProcessFS.cs index b413f31c..afad621e 100644 --- a/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleOutOfProcessFS.cs +++ b/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleOutOfProcessFS.cs @@ -4,12 +4,11 @@ namespace ExcelDna.RuntimeTests { -#if DEBUG [ExcelTestSettings(OutOfProcess = true)] [Collection("OutOfProcess")] public class RegistrationSampleOutOfProcessFS { - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RegistrationSampleFS\bin\Debug\net6.0-windows\ExcelDna.AddIn.RegistrationSampleFS-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RegistrationSampleFS)] public void AsyncSleep() { { @@ -44,7 +43,7 @@ public void AsyncSleep() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RegistrationSampleFS\bin\Debug\net6.0-windows\ExcelDna.AddIn.RegistrationSampleFS-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RegistrationSampleFS)] public void Timer() { { @@ -83,5 +82,4 @@ public void Timer() } } } -#endif } diff --git a/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleVB.cs b/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleVB.cs index 2934cf0f..e3ed9a3e 100644 --- a/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleVB.cs +++ b/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleVB.cs @@ -3,10 +3,9 @@ namespace ExcelDna.RuntimeTests { -#if DEBUG public class RegistrationSampleVB { - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RegistrationSampleVB\bin\Debug\net6.0-windows\ExcelDna.AddIn.RegistrationSampleVB-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RegistrationSampleVB)] public void Optional() { { @@ -21,7 +20,7 @@ public void Optional() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RegistrationSampleVB\bin\Debug\net6.0-windows\ExcelDna.AddIn.RegistrationSampleVB-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RegistrationSampleVB)] public void Params() { { @@ -36,7 +35,7 @@ public void Params() } } - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RegistrationSampleVB\bin\Debug\net6.0-windows\ExcelDna.AddIn.RegistrationSampleVB-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RegistrationSampleVB)] public void Range() { { @@ -56,5 +55,4 @@ public void Range() } } } -#endif } diff --git a/Source/Tests/ExcelDna.RuntimeTests/UserCodeConversions.cs b/Source/Tests/ExcelDna.RuntimeTests/UserCodeConversions.cs index 1ab4193e..6c6d678b 100644 --- a/Source/Tests/ExcelDna.RuntimeTests/UserCodeConversions.cs +++ b/Source/Tests/ExcelDna.RuntimeTests/UserCodeConversions.cs @@ -3,10 +3,9 @@ namespace ExcelDna.RuntimeTests { -#if DEBUG public class UserCodeConversions { - [ExcelFact(Workbook = "", AddIn = @"..\..\..\..\ExcelDna.AddIn.RuntimeTests\bin\Debug\net6.0-windows\ExcelDna.AddIn.RuntimeTests-AddIn")] + [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void ReferenceToRange() { { @@ -16,5 +15,4 @@ public void ReferenceToRange() } } } -#endif } From 2c907cf0dc8ac99074abf217a67ad7b111a7c220 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sun, 16 Feb 2025 13:44:45 +0500 Subject: [PATCH 17/60] Created AOTAddIn test target project. --- .../AOTAddIn/AOTAddIn.csproj | 31 +++++++++++++++++++ .../AOTAddIn/AddIn.cs | 21 +++++++++++++ ...ddIn.Tasks.IntegrationTests.TestTarget.sln | 6 ++++ 3 files changed, 58 insertions(+) create mode 100644 Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/AOTAddIn/AOTAddIn.csproj create mode 100644 Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/AOTAddIn/AddIn.cs diff --git a/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/AOTAddIn/AOTAddIn.csproj b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/AOTAddIn/AOTAddIn.csproj new file mode 100644 index 00000000..3f887ece --- /dev/null +++ b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/AOTAddIn/AOTAddIn.csproj @@ -0,0 +1,31 @@ + + + + net8.0-windows + enable + enable + + win-x64 + true + + + + + ..\..\.exceldna.addin\tools\net6.0-windows7.0\ExcelDna.Integration.dll + + + ..\..\.exceldna.addin\tools\net6.0-windows7.0\ExcelDna.ManagedHost.dll + + + ..\..\.exceldna.addin\tools\net6.0-windows7.0\ExcelDna.Loader.dll + + + + + + + + + + + diff --git a/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/AOTAddIn/AddIn.cs b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/AOTAddIn/AddIn.cs new file mode 100644 index 00000000..c2c63b21 --- /dev/null +++ b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/AOTAddIn/AddIn.cs @@ -0,0 +1,21 @@ +using System.IO; +using System.Windows.Forms; +using ExcelDna.Integration; + +namespace AOTAddIn +{ + public class AddIn : IExcelAddIn + { + public void AutoOpen() + { + var thisAddInName = Path.GetFileName((string)XlCall.Excel(XlCall.xlGetName)); + var message = string.Format("Excel-DNA Add-In '{0}' loaded!", thisAddInName); + + MessageBox.Show(message, thisAddInName, MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + public void AutoClose() + { + } + } +} diff --git a/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget.sln b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget.sln index e1e08d8b..fdeb1c30 100644 --- a/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget.sln +++ b/Source/Tests/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget/ExcelDna.AddIn.Tasks.IntegrationTests.TestTarget.sln @@ -132,6 +132,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NET8RuntimeFrameworkVersion EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AOTMinimal", "AOTMinimal\AOTMinimal.csproj", "{02FE8D18-36B0-47F3-AF76-00D05BC48332}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AOTAddIn", "AOTAddIn\AOTAddIn.csproj", "{43A4D6E9-5C82-530D-889B-D3EDDF43DBF2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -394,6 +396,10 @@ Global {02FE8D18-36B0-47F3-AF76-00D05BC48332}.Debug|Any CPU.Build.0 = Debug|Any CPU {02FE8D18-36B0-47F3-AF76-00D05BC48332}.Release|Any CPU.ActiveCfg = Release|Any CPU {02FE8D18-36B0-47F3-AF76-00D05BC48332}.Release|Any CPU.Build.0 = Release|Any CPU + {43A4D6E9-5C82-530D-889B-D3EDDF43DBF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {43A4D6E9-5C82-530D-889B-D3EDDF43DBF2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {43A4D6E9-5C82-530D-889B-D3EDDF43DBF2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {43A4D6E9-5C82-530D-889B-D3EDDF43DBF2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 5cc54ecc307587ca90777a682ce7630569c9d218 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sun, 16 Feb 2025 13:50:33 +0500 Subject: [PATCH 18/60] Implemented loading of IExcelAddIn(s). --- Source/ExcelDna.Integration/AssemblyLoader.cs | 24 ++++++------ Source/ExcelDna.Integration/DnaLibrary.cs | 1 + Source/ExcelDna.Integration/NativeAOT.cs | 1 + Source/ExcelDna.Integration/TypeHelper.cs | 37 +++++++++++++++++++ .../Generator.cs | 33 ++++++++++++++--- 5 files changed, 79 insertions(+), 17 deletions(-) create mode 100644 Source/ExcelDna.Integration/TypeHelper.cs diff --git a/Source/ExcelDna.Integration/AssemblyLoader.cs b/Source/ExcelDna.Integration/AssemblyLoader.cs index 648d38c4..62880661 100644 --- a/Source/ExcelDna.Integration/AssemblyLoader.cs +++ b/Source/ExcelDna.Integration/AssemblyLoader.cs @@ -89,7 +89,7 @@ public static void ProcessAssemblies( GetExcelMethods(type, explicitExports, methods, excelFunctionsExtendedRegistration); GetExcelFunctionExecutionHandlerSelectors(type, excelFunctionExecutionHandlerSelectors); } - GetExcelAddIns(assembly, type, loadRibbons, addIns); + GetExcelAddIns(assembly, new TypeHelperDynamic(type), loadRibbons, addIns); GetRtdServerTypes(type, rtdServerTypes, out isRtdServer); GetComClassTypes(assembly, type, attribs, isRtdServer, comClassTypes); } @@ -292,38 +292,38 @@ public class ExcelAddInInfo public DnaLibrary ParentDnaLibrary; } - static public void GetExcelAddIns(ExportedAssembly assembly, Type t, bool loadRibbons, List addIns) + static public void GetExcelAddIns(ExportedAssembly assembly, ITypeHelper t, bool loadRibbons, List addIns) { // NOTE: We probably should have restricted this to public types, but didn't. Now it's too late. // So internal classes that implement IExcelAddIn are also loaded. try { - if (!t.IsClass || t.IsAbstract) + if (!t.Type.IsClass || t.Type.IsAbstract) { - Logger.Registration.Verbose("GetExcelAddIns - Skipped add-in object of type: {0}", t.FullName); + Logger.Registration.Verbose("GetExcelAddIns - Skipped add-in object of type: {0}", t.Type.FullName); return; } - Type addInType = t.GetInterface("ExcelDna.Integration.IExcelAddIn"); - bool isRibbon = IsRibbonType(t); + Type addInType = t.Type.GetInterface("ExcelDna.Integration.IExcelAddIn"); + bool isRibbon = IsRibbonType(t.Type); if (addInType != null || (isRibbon && loadRibbons)) { ExcelAddInInfo info = new ExcelAddInInfo(); if (addInType != null) { - info.AutoOpenMethod = addInType.GetMethod("AutoOpen"); - info.AutoCloseMethod = addInType.GetMethod("AutoClose"); + info.AutoOpenMethod = typeof(IExcelAddIn).GetMethod("AutoOpen"); + info.AutoCloseMethod = typeof(IExcelAddIn).GetMethod("AutoClose"); } info.IsCustomUI = isRibbon; - info.Instance = Activator.CreateInstance(t); - info.ParentDnaLibrary = assembly.ParentDnaLibrary; + info.Instance = t.CreateInstance(); + info.ParentDnaLibrary = assembly?.ParentDnaLibrary; addIns.Add(info); - Logger.Registration.Verbose("GetExcelAddIns - Created add-in object of type: {0}", t.FullName); + Logger.Registration.Verbose("GetExcelAddIns - Created add-in object of type: {0}", t.Type.FullName); } } catch (Exception e) // I think only CreateInstance can throw an exception here... { - Logger.Initialization.Warn("GetExcelAddIns CreateInstance problem for type: {0} - exception: {1}", t.FullName, e); + Logger.Initialization.Warn("GetExcelAddIns CreateInstance problem for type: {0} - exception: {1}", t.Type.FullName, e); } } diff --git a/Source/ExcelDna.Integration/DnaLibrary.cs b/Source/ExcelDna.Integration/DnaLibrary.cs index f3d158cc..b8899295 100644 --- a/Source/ExcelDna.Integration/DnaLibrary.cs +++ b/Source/ExcelDna.Integration/DnaLibrary.cs @@ -282,6 +282,7 @@ internal void Initialize() // Recursively get assemblies down .dna tree. _exportedAssemblies = GetAssemblies(dnaResolveRoot); AssemblyLoader.ProcessAssemblies(_exportedAssemblies, _methods, _excelParameterConversions, _excelFunctionProcessors, _excelFunctionsExtendedRegistration, _excelFunctionExecutionHandlerSelectors, _addIns, rtdServerTypes, comClassTypes); + NativeAOT.ExcelAddIns.ForEach(i => AssemblyLoader.GetExcelAddIns(null, i, false, _addIns)); // Register RTD Server Types (i.e. remember that these types are available as RTD servers, with relevant ProgId etc.) RtdRegistration.RegisterRtdServerTypes(rtdServerTypes); diff --git a/Source/ExcelDna.Integration/NativeAOT.cs b/Source/ExcelDna.Integration/NativeAOT.cs index 316ca178..a7cd2cd1 100644 --- a/Source/ExcelDna.Integration/NativeAOT.cs +++ b/Source/ExcelDna.Integration/NativeAOT.cs @@ -8,5 +8,6 @@ public class NativeAOT public static bool IsActive { get; set; } public static List MethodsForRegistration { get; } = new List(); + public static List ExcelAddIns { get; } = new List(); } } diff --git a/Source/ExcelDna.Integration/TypeHelper.cs b/Source/ExcelDna.Integration/TypeHelper.cs new file mode 100644 index 00000000..46936f35 --- /dev/null +++ b/Source/ExcelDna.Integration/TypeHelper.cs @@ -0,0 +1,37 @@ +using System; +using System.Linq; +using System.Reflection; + +namespace ExcelDna.Integration +{ + public interface ITypeHelper + { + Type Type { get; } + object CreateInstance(); + } + + public class TypeHelper : ITypeHelper + { + public Type Type => typeof(T); + + public object CreateInstance() + { + return Activator.CreateInstance(); + } + } + + public class TypeHelperDynamic : ITypeHelper + { + public TypeHelperDynamic(Type t) + { + Type = t; + } + + public Type Type { get; } + + public object CreateInstance() + { + return Activator.CreateInstance(Type); + } + } +} diff --git a/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs b/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs index c5466e7c..14c45eab 100644 --- a/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs +++ b/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs @@ -30,6 +30,8 @@ public static short Initialize(void* xlAddInExportInfoAddress, void* hModuleXll, { ExcelDna.Integration.NativeAOT.IsActive = true; + [ADDINS] + [FUNCTIONS] return ExcelDna.ManagedHost.AddInInitialize.InitializeNativeAOT(xlAddInExportInfoAddress, hModuleXll, pPathXLL, disableAssemblyContextUnload, pTempDirPath); @@ -37,13 +39,22 @@ public static short Initialize(void* xlAddInExportInfoAddress, void* hModuleXll, } } """; - string functions = ""; - foreach (var i in receiver.Functions) { - functions += $"ExcelDna.Integration.NativeAOT.MethodsForRegistration.Add(typeof({i.ContainingType}).GetMethod(\"{i.Name}\")!);\r\n"; + string addIns = ""; + foreach (var i in receiver.AddIns) + { + addIns += $"ExcelDna.Integration.NativeAOT.ExcelAddIns.Add(new ExcelDna.Integration.TypeHelper<{Util.GetFullTypeName(i)}>());\r\n"; + } + source = source.Replace("[ADDINS]", addIns); + } + { + string functions = ""; + foreach (var i in receiver.Functions) + { + functions += $"ExcelDna.Integration.NativeAOT.MethodsForRegistration.Add(typeof({Util.GetFullTypeName(i.ContainingType)}).GetMethod(\"{i.Name}\")!);\r\n"; + } + source = source.Replace("[FUNCTIONS]", functions); } - - source = source.Replace("[FUNCTIONS]", functions); context.AddSource($"ExcelDna.SG.NAOT.Init.g.cs", source); } @@ -56,6 +67,7 @@ public void Initialize(GeneratorInitializationContext context) class SyntaxReceiver : ISyntaxContextReceiver { public List Functions { get; } = new List(); + public List AddIns { get; } = new List(); public void OnVisitSyntaxNode(GeneratorSyntaxContext context) { @@ -65,6 +77,17 @@ public void OnVisitSyntaxNode(GeneratorSyntaxContext context) if (methodSymbol.GetAttributes().Any(a => a.AttributeClass?.ToDisplayString(fullNameFormat) == "ExcelDna.Integration.ExcelFunctionAttribute")) Functions.Add(methodSymbol); } + + if (context.Node is ClassDeclarationSyntax classSyntax) + { + if (context.SemanticModel.GetDeclaredSymbol(classSyntax) is ITypeSymbol typeSymbol) + { + if (typeSymbol.AllInterfaces.Any(i => Util.GetFullTypeName(i) == "ExcelDna.Integration.IExcelAddIn")) + { + AddIns.Add(typeSymbol); + } + } + } } private static SymbolDisplayFormat fullNameFormat = new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces); From 8990b3acf27a45093029722b0ca1ded9e7f4471e Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sun, 16 Feb 2025 17:49:04 +0500 Subject: [PATCH 19/60] Added AddIn64 suffix to the published .xll. --- .../build/ExcelDna.AddIn.NativeAOT.targets | 22 ++++++++----------- .../PackExcelAddInNativeAOT.cs | 22 ++++++++++++++++--- .../ExcelDna.PackedResources/ExcelDnaPack.cs | 4 +--- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/Package/ExcelDna.AddIn.NativeAOT/build/ExcelDna.AddIn.NativeAOT.targets b/Package/ExcelDna.AddIn.NativeAOT/build/ExcelDna.AddIn.NativeAOT.targets index 0bb91067..ddfec19e 100644 --- a/Package/ExcelDna.AddIn.NativeAOT/build/ExcelDna.AddIn.NativeAOT.targets +++ b/Package/ExcelDna.AddIn.NativeAOT/build/ExcelDna.AddIn.NativeAOT.targets @@ -22,18 +22,14 @@ - - - - - + + + diff --git a/Source/ExcelDna.AddIn.Tasks/PackExcelAddInNativeAOT.cs b/Source/ExcelDna.AddIn.Tasks/PackExcelAddInNativeAOT.cs index a6d21c9a..a120d85b 100644 --- a/Source/ExcelDna.AddIn.Tasks/PackExcelAddInNativeAOT.cs +++ b/Source/ExcelDna.AddIn.Tasks/PackExcelAddInNativeAOT.cs @@ -35,7 +35,11 @@ public override bool Execute() useManagedResourceResolver = PackManagedOnWindows || !OperatingSystem.IsWindows(); #endif - int result = ExcelDna.PackedResources.ExcelDnaPack.PackNativeAOT(OutputPackedXllFileName, RunMultithreaded, useManagedResourceResolver, _log); + string mainNativeAssembly = Path.Combine(PublishDir, ProjectName + ".dll"); + string xllOutput = Path.Combine(PublishDir, ProjectName + "-AddIn64.xll"); + File.Copy(Xll64FilePath, xllOutput, true); + + int result = ExcelDna.PackedResources.ExcelDnaPack.PackNativeAOT(mainNativeAssembly, xllOutput, RunMultithreaded, useManagedResourceResolver, _log); if (result != 0) throw new ApplicationException($"Pack failed with exit code {result}."); @@ -50,10 +54,22 @@ public override bool Execute() } /// - /// Output path + /// The 64-bit .xll file path + /// + [Required] + public string Xll64FilePath { get; set; } + + /// + /// The name of the project being compiled + /// + [Required] + public string ProjectName { get; set; } + + /// + /// The output location for the publish target; includes the trailing backslash (\). /// [Required] - public string OutputPackedXllFileName { get; set; } + public string PublishDir { get; set; } /// /// Use multi threading diff --git a/Source/ExcelDna.PackedResources/ExcelDnaPack.cs b/Source/ExcelDna.PackedResources/ExcelDnaPack.cs index f83495b4..6c7e0f44 100644 --- a/Source/ExcelDna.PackedResources/ExcelDnaPack.cs +++ b/Source/ExcelDna.PackedResources/ExcelDnaPack.cs @@ -150,10 +150,8 @@ public static int Pack(string dnaPath, string xllOutputPathParam, bool compress, return 0; } - public static int PackNativeAOT(string xllOutput, bool multithreading, bool useManagedResourceResolver, IBuildLogger buildLogger) + public static int PackNativeAOT(string mainNativeAssembly, string xllOutput, bool multithreading, bool useManagedResourceResolver, IBuildLogger buildLogger) { - string mainNativeAssembly = Path.ChangeExtension(xllOutput, "dll"); - ResourceHelper.ResourceUpdater ru = new ResourceHelper.ResourceUpdater(xllOutput, useManagedResourceResolver, buildLogger); ru.AddFile(File.ReadAllBytes(mainNativeAssembly), "__MAIN__", ResourceHelper.TypeName.NATIVE_ASSEMBLY, null, false, multithreading); // Name here must exactly match name in host.cpp. ru.EndUpdate(); From af33c95f6687248af74be93458df06777f4fa1b1 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sat, 1 Mar 2025 16:17:32 +0500 Subject: [PATCH 20/60] Added support for ExcelCommand registration. --- Source/ExcelDna.Loader/MarshalNativeAOT.cs | 518 ++++++++++++++++++ .../Generator.cs | 4 +- .../Commands.cs | 13 + 3 files changed, 534 insertions(+), 1 deletion(-) create mode 100644 Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/Commands.cs diff --git a/Source/ExcelDna.Loader/MarshalNativeAOT.cs b/Source/ExcelDna.Loader/MarshalNativeAOT.cs index f671ce1b..16af6ca2 100644 --- a/Source/ExcelDna.Loader/MarshalNativeAOT.cs +++ b/Source/ExcelDna.Loader/MarshalNativeAOT.cs @@ -526,6 +526,524 @@ public static IntPtr GetFunctionPointerForDelegate(Delegate d, XlMethodInfo meth return Marshal.GetFunctionPointerForDelegate((XlFunc255)d); } } + else + { + switch (methodInfo.Parameters.Length) + { + case 0: + return Marshal.GetFunctionPointerForDelegate((XlAct0)d); + case 1: + return Marshal.GetFunctionPointerForDelegate((XlAct1)d); + case 2: + return Marshal.GetFunctionPointerForDelegate((XlAct2)d); + case 3: + return Marshal.GetFunctionPointerForDelegate((XlAct3)d); + case 4: + return Marshal.GetFunctionPointerForDelegate((XlAct4)d); + case 5: + return Marshal.GetFunctionPointerForDelegate((XlAct5)d); + case 6: + return Marshal.GetFunctionPointerForDelegate((XlAct6)d); + case 7: + return Marshal.GetFunctionPointerForDelegate((XlAct7)d); + case 8: + return Marshal.GetFunctionPointerForDelegate((XlAct8)d); + case 9: + return Marshal.GetFunctionPointerForDelegate((XlAct9)d); + case 10: + return Marshal.GetFunctionPointerForDelegate((XlAct10)d); + case 11: + return Marshal.GetFunctionPointerForDelegate((XlAct11)d); + case 12: + return Marshal.GetFunctionPointerForDelegate((XlAct12)d); + case 13: + return Marshal.GetFunctionPointerForDelegate((XlAct13)d); + case 14: + return Marshal.GetFunctionPointerForDelegate((XlAct14)d); + case 15: + return Marshal.GetFunctionPointerForDelegate((XlAct15)d); + case 16: + return Marshal.GetFunctionPointerForDelegate((XlAct16)d); + case 17: + return Marshal.GetFunctionPointerForDelegate((XlAct17)d); + case 18: + return Marshal.GetFunctionPointerForDelegate((XlAct18)d); + case 19: + return Marshal.GetFunctionPointerForDelegate((XlAct19)d); + case 20: + return Marshal.GetFunctionPointerForDelegate((XlAct20)d); + case 21: + return Marshal.GetFunctionPointerForDelegate((XlAct21)d); + case 22: + return Marshal.GetFunctionPointerForDelegate((XlAct22)d); + case 23: + return Marshal.GetFunctionPointerForDelegate((XlAct23)d); + case 24: + return Marshal.GetFunctionPointerForDelegate((XlAct24)d); + case 25: + return Marshal.GetFunctionPointerForDelegate((XlAct25)d); + case 26: + return Marshal.GetFunctionPointerForDelegate((XlAct26)d); + case 27: + return Marshal.GetFunctionPointerForDelegate((XlAct27)d); + case 28: + return Marshal.GetFunctionPointerForDelegate((XlAct28)d); + case 29: + return Marshal.GetFunctionPointerForDelegate((XlAct29)d); + case 30: + return Marshal.GetFunctionPointerForDelegate((XlAct30)d); + case 31: + return Marshal.GetFunctionPointerForDelegate((XlAct31)d); + case 32: + return Marshal.GetFunctionPointerForDelegate((XlAct32)d); + case 33: + return Marshal.GetFunctionPointerForDelegate((XlAct33)d); + case 34: + return Marshal.GetFunctionPointerForDelegate((XlAct34)d); + case 35: + return Marshal.GetFunctionPointerForDelegate((XlAct35)d); + case 36: + return Marshal.GetFunctionPointerForDelegate((XlAct36)d); + case 37: + return Marshal.GetFunctionPointerForDelegate((XlAct37)d); + case 38: + return Marshal.GetFunctionPointerForDelegate((XlAct38)d); + case 39: + return Marshal.GetFunctionPointerForDelegate((XlAct39)d); + case 40: + return Marshal.GetFunctionPointerForDelegate((XlAct40)d); + case 41: + return Marshal.GetFunctionPointerForDelegate((XlAct41)d); + case 42: + return Marshal.GetFunctionPointerForDelegate((XlAct42)d); + case 43: + return Marshal.GetFunctionPointerForDelegate((XlAct43)d); + case 44: + return Marshal.GetFunctionPointerForDelegate((XlAct44)d); + case 45: + return Marshal.GetFunctionPointerForDelegate((XlAct45)d); + case 46: + return Marshal.GetFunctionPointerForDelegate((XlAct46)d); + case 47: + return Marshal.GetFunctionPointerForDelegate((XlAct47)d); + case 48: + return Marshal.GetFunctionPointerForDelegate((XlAct48)d); + case 49: + return Marshal.GetFunctionPointerForDelegate((XlAct49)d); + case 50: + return Marshal.GetFunctionPointerForDelegate((XlAct50)d); + case 51: + return Marshal.GetFunctionPointerForDelegate((XlAct51)d); + case 52: + return Marshal.GetFunctionPointerForDelegate((XlAct52)d); + case 53: + return Marshal.GetFunctionPointerForDelegate((XlAct53)d); + case 54: + return Marshal.GetFunctionPointerForDelegate((XlAct54)d); + case 55: + return Marshal.GetFunctionPointerForDelegate((XlAct55)d); + case 56: + return Marshal.GetFunctionPointerForDelegate((XlAct56)d); + case 57: + return Marshal.GetFunctionPointerForDelegate((XlAct57)d); + case 58: + return Marshal.GetFunctionPointerForDelegate((XlAct58)d); + case 59: + return Marshal.GetFunctionPointerForDelegate((XlAct59)d); + case 60: + return Marshal.GetFunctionPointerForDelegate((XlAct60)d); + case 61: + return Marshal.GetFunctionPointerForDelegate((XlAct61)d); + case 62: + return Marshal.GetFunctionPointerForDelegate((XlAct62)d); + case 63: + return Marshal.GetFunctionPointerForDelegate((XlAct63)d); + case 64: + return Marshal.GetFunctionPointerForDelegate((XlAct64)d); + case 65: + return Marshal.GetFunctionPointerForDelegate((XlAct65)d); + case 66: + return Marshal.GetFunctionPointerForDelegate((XlAct66)d); + case 67: + return Marshal.GetFunctionPointerForDelegate((XlAct67)d); + case 68: + return Marshal.GetFunctionPointerForDelegate((XlAct68)d); + case 69: + return Marshal.GetFunctionPointerForDelegate((XlAct69)d); + case 70: + return Marshal.GetFunctionPointerForDelegate((XlAct70)d); + case 71: + return Marshal.GetFunctionPointerForDelegate((XlAct71)d); + case 72: + return Marshal.GetFunctionPointerForDelegate((XlAct72)d); + case 73: + return Marshal.GetFunctionPointerForDelegate((XlAct73)d); + case 74: + return Marshal.GetFunctionPointerForDelegate((XlAct74)d); + case 75: + return Marshal.GetFunctionPointerForDelegate((XlAct75)d); + case 76: + return Marshal.GetFunctionPointerForDelegate((XlAct76)d); + case 77: + return Marshal.GetFunctionPointerForDelegate((XlAct77)d); + case 78: + return Marshal.GetFunctionPointerForDelegate((XlAct78)d); + case 79: + return Marshal.GetFunctionPointerForDelegate((XlAct79)d); + case 80: + return Marshal.GetFunctionPointerForDelegate((XlAct80)d); + case 81: + return Marshal.GetFunctionPointerForDelegate((XlAct81)d); + case 82: + return Marshal.GetFunctionPointerForDelegate((XlAct82)d); + case 83: + return Marshal.GetFunctionPointerForDelegate((XlAct83)d); + case 84: + return Marshal.GetFunctionPointerForDelegate((XlAct84)d); + case 85: + return Marshal.GetFunctionPointerForDelegate((XlAct85)d); + case 86: + return Marshal.GetFunctionPointerForDelegate((XlAct86)d); + case 87: + return Marshal.GetFunctionPointerForDelegate((XlAct87)d); + case 88: + return Marshal.GetFunctionPointerForDelegate((XlAct88)d); + case 89: + return Marshal.GetFunctionPointerForDelegate((XlAct89)d); + case 90: + return Marshal.GetFunctionPointerForDelegate((XlAct90)d); + case 91: + return Marshal.GetFunctionPointerForDelegate((XlAct91)d); + case 92: + return Marshal.GetFunctionPointerForDelegate((XlAct92)d); + case 93: + return Marshal.GetFunctionPointerForDelegate((XlAct93)d); + case 94: + return Marshal.GetFunctionPointerForDelegate((XlAct94)d); + case 95: + return Marshal.GetFunctionPointerForDelegate((XlAct95)d); + case 96: + return Marshal.GetFunctionPointerForDelegate((XlAct96)d); + case 97: + return Marshal.GetFunctionPointerForDelegate((XlAct97)d); + case 98: + return Marshal.GetFunctionPointerForDelegate((XlAct98)d); + case 99: + return Marshal.GetFunctionPointerForDelegate((XlAct99)d); + case 100: + return Marshal.GetFunctionPointerForDelegate((XlAct100)d); + case 101: + return Marshal.GetFunctionPointerForDelegate((XlAct101)d); + case 102: + return Marshal.GetFunctionPointerForDelegate((XlAct102)d); + case 103: + return Marshal.GetFunctionPointerForDelegate((XlAct103)d); + case 104: + return Marshal.GetFunctionPointerForDelegate((XlAct104)d); + case 105: + return Marshal.GetFunctionPointerForDelegate((XlAct105)d); + case 106: + return Marshal.GetFunctionPointerForDelegate((XlAct106)d); + case 107: + return Marshal.GetFunctionPointerForDelegate((XlAct107)d); + case 108: + return Marshal.GetFunctionPointerForDelegate((XlAct108)d); + case 109: + return Marshal.GetFunctionPointerForDelegate((XlAct109)d); + case 110: + return Marshal.GetFunctionPointerForDelegate((XlAct110)d); + case 111: + return Marshal.GetFunctionPointerForDelegate((XlAct111)d); + case 112: + return Marshal.GetFunctionPointerForDelegate((XlAct112)d); + case 113: + return Marshal.GetFunctionPointerForDelegate((XlAct113)d); + case 114: + return Marshal.GetFunctionPointerForDelegate((XlAct114)d); + case 115: + return Marshal.GetFunctionPointerForDelegate((XlAct115)d); + case 116: + return Marshal.GetFunctionPointerForDelegate((XlAct116)d); + case 117: + return Marshal.GetFunctionPointerForDelegate((XlAct117)d); + case 118: + return Marshal.GetFunctionPointerForDelegate((XlAct118)d); + case 119: + return Marshal.GetFunctionPointerForDelegate((XlAct119)d); + case 120: + return Marshal.GetFunctionPointerForDelegate((XlAct120)d); + case 121: + return Marshal.GetFunctionPointerForDelegate((XlAct121)d); + case 122: + return Marshal.GetFunctionPointerForDelegate((XlAct122)d); + case 123: + return Marshal.GetFunctionPointerForDelegate((XlAct123)d); + case 124: + return Marshal.GetFunctionPointerForDelegate((XlAct124)d); + case 125: + return Marshal.GetFunctionPointerForDelegate((XlAct125)d); + case 126: + return Marshal.GetFunctionPointerForDelegate((XlAct126)d); + case 127: + return Marshal.GetFunctionPointerForDelegate((XlAct127)d); + case 128: + return Marshal.GetFunctionPointerForDelegate((XlAct128)d); + case 129: + return Marshal.GetFunctionPointerForDelegate((XlAct129)d); + case 130: + return Marshal.GetFunctionPointerForDelegate((XlAct130)d); + case 131: + return Marshal.GetFunctionPointerForDelegate((XlAct131)d); + case 132: + return Marshal.GetFunctionPointerForDelegate((XlAct132)d); + case 133: + return Marshal.GetFunctionPointerForDelegate((XlAct133)d); + case 134: + return Marshal.GetFunctionPointerForDelegate((XlAct134)d); + case 135: + return Marshal.GetFunctionPointerForDelegate((XlAct135)d); + case 136: + return Marshal.GetFunctionPointerForDelegate((XlAct136)d); + case 137: + return Marshal.GetFunctionPointerForDelegate((XlAct137)d); + case 138: + return Marshal.GetFunctionPointerForDelegate((XlAct138)d); + case 139: + return Marshal.GetFunctionPointerForDelegate((XlAct139)d); + case 140: + return Marshal.GetFunctionPointerForDelegate((XlAct140)d); + case 141: + return Marshal.GetFunctionPointerForDelegate((XlAct141)d); + case 142: + return Marshal.GetFunctionPointerForDelegate((XlAct142)d); + case 143: + return Marshal.GetFunctionPointerForDelegate((XlAct143)d); + case 144: + return Marshal.GetFunctionPointerForDelegate((XlAct144)d); + case 145: + return Marshal.GetFunctionPointerForDelegate((XlAct145)d); + case 146: + return Marshal.GetFunctionPointerForDelegate((XlAct146)d); + case 147: + return Marshal.GetFunctionPointerForDelegate((XlAct147)d); + case 148: + return Marshal.GetFunctionPointerForDelegate((XlAct148)d); + case 149: + return Marshal.GetFunctionPointerForDelegate((XlAct149)d); + case 150: + return Marshal.GetFunctionPointerForDelegate((XlAct150)d); + case 151: + return Marshal.GetFunctionPointerForDelegate((XlAct151)d); + case 152: + return Marshal.GetFunctionPointerForDelegate((XlAct152)d); + case 153: + return Marshal.GetFunctionPointerForDelegate((XlAct153)d); + case 154: + return Marshal.GetFunctionPointerForDelegate((XlAct154)d); + case 155: + return Marshal.GetFunctionPointerForDelegate((XlAct155)d); + case 156: + return Marshal.GetFunctionPointerForDelegate((XlAct156)d); + case 157: + return Marshal.GetFunctionPointerForDelegate((XlAct157)d); + case 158: + return Marshal.GetFunctionPointerForDelegate((XlAct158)d); + case 159: + return Marshal.GetFunctionPointerForDelegate((XlAct159)d); + case 160: + return Marshal.GetFunctionPointerForDelegate((XlAct160)d); + case 161: + return Marshal.GetFunctionPointerForDelegate((XlAct161)d); + case 162: + return Marshal.GetFunctionPointerForDelegate((XlAct162)d); + case 163: + return Marshal.GetFunctionPointerForDelegate((XlAct163)d); + case 164: + return Marshal.GetFunctionPointerForDelegate((XlAct164)d); + case 165: + return Marshal.GetFunctionPointerForDelegate((XlAct165)d); + case 166: + return Marshal.GetFunctionPointerForDelegate((XlAct166)d); + case 167: + return Marshal.GetFunctionPointerForDelegate((XlAct167)d); + case 168: + return Marshal.GetFunctionPointerForDelegate((XlAct168)d); + case 169: + return Marshal.GetFunctionPointerForDelegate((XlAct169)d); + case 170: + return Marshal.GetFunctionPointerForDelegate((XlAct170)d); + case 171: + return Marshal.GetFunctionPointerForDelegate((XlAct171)d); + case 172: + return Marshal.GetFunctionPointerForDelegate((XlAct172)d); + case 173: + return Marshal.GetFunctionPointerForDelegate((XlAct173)d); + case 174: + return Marshal.GetFunctionPointerForDelegate((XlAct174)d); + case 175: + return Marshal.GetFunctionPointerForDelegate((XlAct175)d); + case 176: + return Marshal.GetFunctionPointerForDelegate((XlAct176)d); + case 177: + return Marshal.GetFunctionPointerForDelegate((XlAct177)d); + case 178: + return Marshal.GetFunctionPointerForDelegate((XlAct178)d); + case 179: + return Marshal.GetFunctionPointerForDelegate((XlAct179)d); + case 180: + return Marshal.GetFunctionPointerForDelegate((XlAct180)d); + case 181: + return Marshal.GetFunctionPointerForDelegate((XlAct181)d); + case 182: + return Marshal.GetFunctionPointerForDelegate((XlAct182)d); + case 183: + return Marshal.GetFunctionPointerForDelegate((XlAct183)d); + case 184: + return Marshal.GetFunctionPointerForDelegate((XlAct184)d); + case 185: + return Marshal.GetFunctionPointerForDelegate((XlAct185)d); + case 186: + return Marshal.GetFunctionPointerForDelegate((XlAct186)d); + case 187: + return Marshal.GetFunctionPointerForDelegate((XlAct187)d); + case 188: + return Marshal.GetFunctionPointerForDelegate((XlAct188)d); + case 189: + return Marshal.GetFunctionPointerForDelegate((XlAct189)d); + case 190: + return Marshal.GetFunctionPointerForDelegate((XlAct190)d); + case 191: + return Marshal.GetFunctionPointerForDelegate((XlAct191)d); + case 192: + return Marshal.GetFunctionPointerForDelegate((XlAct192)d); + case 193: + return Marshal.GetFunctionPointerForDelegate((XlAct193)d); + case 194: + return Marshal.GetFunctionPointerForDelegate((XlAct194)d); + case 195: + return Marshal.GetFunctionPointerForDelegate((XlAct195)d); + case 196: + return Marshal.GetFunctionPointerForDelegate((XlAct196)d); + case 197: + return Marshal.GetFunctionPointerForDelegate((XlAct197)d); + case 198: + return Marshal.GetFunctionPointerForDelegate((XlAct198)d); + case 199: + return Marshal.GetFunctionPointerForDelegate((XlAct199)d); + case 200: + return Marshal.GetFunctionPointerForDelegate((XlAct200)d); + case 201: + return Marshal.GetFunctionPointerForDelegate((XlAct201)d); + case 202: + return Marshal.GetFunctionPointerForDelegate((XlAct202)d); + case 203: + return Marshal.GetFunctionPointerForDelegate((XlAct203)d); + case 204: + return Marshal.GetFunctionPointerForDelegate((XlAct204)d); + case 205: + return Marshal.GetFunctionPointerForDelegate((XlAct205)d); + case 206: + return Marshal.GetFunctionPointerForDelegate((XlAct206)d); + case 207: + return Marshal.GetFunctionPointerForDelegate((XlAct207)d); + case 208: + return Marshal.GetFunctionPointerForDelegate((XlAct208)d); + case 209: + return Marshal.GetFunctionPointerForDelegate((XlAct209)d); + case 210: + return Marshal.GetFunctionPointerForDelegate((XlAct210)d); + case 211: + return Marshal.GetFunctionPointerForDelegate((XlAct211)d); + case 212: + return Marshal.GetFunctionPointerForDelegate((XlAct212)d); + case 213: + return Marshal.GetFunctionPointerForDelegate((XlAct213)d); + case 214: + return Marshal.GetFunctionPointerForDelegate((XlAct214)d); + case 215: + return Marshal.GetFunctionPointerForDelegate((XlAct215)d); + case 216: + return Marshal.GetFunctionPointerForDelegate((XlAct216)d); + case 217: + return Marshal.GetFunctionPointerForDelegate((XlAct217)d); + case 218: + return Marshal.GetFunctionPointerForDelegate((XlAct218)d); + case 219: + return Marshal.GetFunctionPointerForDelegate((XlAct219)d); + case 220: + return Marshal.GetFunctionPointerForDelegate((XlAct220)d); + case 221: + return Marshal.GetFunctionPointerForDelegate((XlAct221)d); + case 222: + return Marshal.GetFunctionPointerForDelegate((XlAct222)d); + case 223: + return Marshal.GetFunctionPointerForDelegate((XlAct223)d); + case 224: + return Marshal.GetFunctionPointerForDelegate((XlAct224)d); + case 225: + return Marshal.GetFunctionPointerForDelegate((XlAct225)d); + case 226: + return Marshal.GetFunctionPointerForDelegate((XlAct226)d); + case 227: + return Marshal.GetFunctionPointerForDelegate((XlAct227)d); + case 228: + return Marshal.GetFunctionPointerForDelegate((XlAct228)d); + case 229: + return Marshal.GetFunctionPointerForDelegate((XlAct229)d); + case 230: + return Marshal.GetFunctionPointerForDelegate((XlAct230)d); + case 231: + return Marshal.GetFunctionPointerForDelegate((XlAct231)d); + case 232: + return Marshal.GetFunctionPointerForDelegate((XlAct232)d); + case 233: + return Marshal.GetFunctionPointerForDelegate((XlAct233)d); + case 234: + return Marshal.GetFunctionPointerForDelegate((XlAct234)d); + case 235: + return Marshal.GetFunctionPointerForDelegate((XlAct235)d); + case 236: + return Marshal.GetFunctionPointerForDelegate((XlAct236)d); + case 237: + return Marshal.GetFunctionPointerForDelegate((XlAct237)d); + case 238: + return Marshal.GetFunctionPointerForDelegate((XlAct238)d); + case 239: + return Marshal.GetFunctionPointerForDelegate((XlAct239)d); + case 240: + return Marshal.GetFunctionPointerForDelegate((XlAct240)d); + case 241: + return Marshal.GetFunctionPointerForDelegate((XlAct241)d); + case 242: + return Marshal.GetFunctionPointerForDelegate((XlAct242)d); + case 243: + return Marshal.GetFunctionPointerForDelegate((XlAct243)d); + case 244: + return Marshal.GetFunctionPointerForDelegate((XlAct244)d); + case 245: + return Marshal.GetFunctionPointerForDelegate((XlAct245)d); + case 246: + return Marshal.GetFunctionPointerForDelegate((XlAct246)d); + case 247: + return Marshal.GetFunctionPointerForDelegate((XlAct247)d); + case 248: + return Marshal.GetFunctionPointerForDelegate((XlAct248)d); + case 249: + return Marshal.GetFunctionPointerForDelegate((XlAct249)d); + case 250: + return Marshal.GetFunctionPointerForDelegate((XlAct250)d); + case 251: + return Marshal.GetFunctionPointerForDelegate((XlAct251)d); + case 252: + return Marshal.GetFunctionPointerForDelegate((XlAct252)d); + case 253: + return Marshal.GetFunctionPointerForDelegate((XlAct253)d); + case 254: + return Marshal.GetFunctionPointerForDelegate((XlAct254)d); + case 255: + return Marshal.GetFunctionPointerForDelegate((XlAct255)d); + } + } throw new NotImplementedException("GetFunctionPointerForDelegate"); } diff --git a/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs b/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs index 14c45eab..7d649088 100644 --- a/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs +++ b/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs @@ -74,7 +74,9 @@ public void OnVisitSyntaxNode(GeneratorSyntaxContext context) if (context.Node is MethodDeclarationSyntax methodSyntax) { IMethodSymbol methodSymbol = (context.SemanticModel.GetDeclaredSymbol(methodSyntax) as IMethodSymbol)!; - if (methodSymbol.GetAttributes().Any(a => a.AttributeClass?.ToDisplayString(fullNameFormat) == "ExcelDna.Integration.ExcelFunctionAttribute")) + if (methodSymbol.GetAttributes().Any(a => + a.AttributeClass?.ToDisplayString(fullNameFormat) == "ExcelDna.Integration.ExcelFunctionAttribute" || + a.AttributeClass?.ToDisplayString(fullNameFormat) == "ExcelDna.Integration.ExcelCommandAttribute")) Functions.Add(methodSymbol); } diff --git a/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/Commands.cs b/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/Commands.cs new file mode 100644 index 00000000..4352ef67 --- /dev/null +++ b/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/Commands.cs @@ -0,0 +1,13 @@ +using ExcelDna.Integration; + +namespace ExcelDna.AddIn.RuntimeTestsAOT +{ + public class Commands + { + [ExcelCommand(MenuText = "")] + public static void NativeCommand() + { + System.Diagnostics.Trace.WriteLine("RuntimeTestsAOT NativeCommand"); + } + } +} From c56cd5be8c19da80bfe4733c5d1b179bdefaccdb Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sun, 9 Mar 2025 22:46:21 +0500 Subject: [PATCH 21/60] Trying to add a command to a ribbon. Work in progress... --- .../ComApi/ComClass.cs | 28 +++ .../ComApi/ExcelObject.cs | 196 +++++++++++++++++ .../ComApi/ICommandBarControl.cs | 33 +++ .../ComApi/IDispatch.cs | 39 ++++ .../ExcelDna.COMWrappers.NativeAOT/Excel.cs | 115 ++++++++++ .../ExcelDna.COMWrappers.NativeAOT.csproj | 14 ++ .../OpenWindowGetter.cs | 53 +++++ .../TypeAdapter.cs | 52 +++++ .../Types/Managed/DispParams.cs | 9 + .../Types/Managed/ExcepInfo.cs | 53 +++++ .../Types/Managed/Variant.cs | 11 + .../Types/Managed/XlOper.cs | 60 +++++ .../Types/Marshalling/Array.cs | 31 +++ .../Types/Marshalling/DispParams.cs | 35 +++ .../Types/Marshalling/ExcepInfo.cs | 45 ++++ .../Types/Marshalling/Variant.cs | 60 +++++ .../Types/Unmanaged/ClsCtx.cs | 33 +++ .../Types/Unmanaged/ComConstants.cs | 9 + .../Types/Unmanaged/DispParams.cs | 12 + .../Types/Unmanaged/ExcelConstants.cs | 100 +++++++++ .../Types/Unmanaged/ExcepInfo.cs | 17 ++ .../Types/Unmanaged/Variant.cs | 208 ++++++++++++++++++ .../Types/Unmanaged/VariantBool.cs | 7 + .../Types/Unmanaged/VariantType.cs | 57 +++++ .../Types/Unmanaged/XlOper12.cs | 178 +++++++++++++++ Source/ExcelDna.COMWrappers.NativeAOT/Util.cs | 23 ++ Source/ExcelDna.Integration/ComInterop.cs | 81 +++++-- .../ExcelDna.Integration/ExcelCommandBars.cs | 92 +++++--- Source/ExcelDna.Integration/ICommandBars.cs | 17 ++ Source/ExcelDna.Integration/MenuManager.cs | 20 +- Source/ExcelDna.Integration/NativeAOT.cs | 2 + .../Generator.cs | 2 + Source/ExcelDna.sln | 10 + .../Commands.cs | 2 +- .../ExcelDna.AddIn.RuntimeTestsAOT.csproj | 3 +- 35 files changed, 1650 insertions(+), 57 deletions(-) create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ComClass.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ExcelObject.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ICommandBarControl.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComApi/IDispatch.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Excel.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ExcelDna.COMWrappers.NativeAOT.csproj create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/OpenWindowGetter.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/DispParams.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/ExcepInfo.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/Variant.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/XlOper.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Array.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/DispParams.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/ExcepInfo.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Variant.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ClsCtx.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ComConstants.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/DispParams.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ExcelConstants.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ExcepInfo.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/Variant.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/VariantBool.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/VariantType.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/XlOper12.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Util.cs create mode 100644 Source/ExcelDna.Integration/ICommandBars.cs diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ComClass.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ComClass.cs new file mode 100644 index 00000000..5a0b6853 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ComClass.cs @@ -0,0 +1,28 @@ +using Addin.Types.Unmanaged; +using System.Runtime.InteropServices; + +namespace Addin.ComApi; + +public partial class ComClass +{ + [LibraryImport("ole32.dll")] + public static partial int CoCreateInstance( + ref Guid rclsid, + nint pUnkOuter, + ClsCtx dwClsContext, + ref Guid riid, + out IDispatch ppv + ); + + public static IDispatch Create(Guid clsid, ClsCtx server) + { + var guid = typeof(IDispatch).GUID; + + int hr = CoCreateInstance(ref clsid, nint.Zero, server, ref guid, out IDispatch obj); + if (hr < 0) + { + Marshal.ThrowExceptionForHR(hr); + } + return obj; + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ExcelObject.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ExcelObject.cs new file mode 100644 index 00000000..ff6b4d01 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ExcelObject.cs @@ -0,0 +1,196 @@ +using Addin.Types.Managed; +using System.Dynamic; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; +using static Addin.Types.Unmanaged.ComConstants; +using Unmanaged = Addin.Types.Unmanaged; + +namespace Addin.ComApi; + +public class ExcelObject : DynamicObject +{ + public IDispatch _interfacePtr; + Guid emptyGuid = Guid.Empty; + bool _verbose; + + public ExcelObject(IDispatch? interfacePtr = null) + { + if (interfacePtr != null) + { + _interfacePtr = interfacePtr; + return; + } + + //// The CLSID for Excel.Application (COMView.exe->CLSID table) + //var clsid = new Guid("{00024500-0000-0000-C000-000000000046}"); + + //// COMView.exe -> CLSID table -> Type column + //var server = Unmanaged.ClsCtx.CLSCTX_LOCAL_SERVER; + + //_interfacePtr = ComClass.Create(clsid, server); + } + + public object? GetProperty(string name) + { + DispParams dispParams = new(); + + return InvokeWrapper(name, INVOKEKIND.INVOKE_PROPERTYGET, dispParams); + } + + public override bool TryGetMember(GetMemberBinder binder, out object? result) + { + DispParams dispParams = new(); + + result = InvokeWrapper(binder.Name, INVOKEKIND.INVOKE_PROPERTYGET, dispParams); + + return true; + } + + public override bool TrySetMember(SetMemberBinder binder, object value) + { + var dispParams = new DispParams + { + rgvarg = [new Variant(value)], + rgdispidNamedArgs = DISPID_PROPERTYPUT, + cArgs = 1, + cNamedArgs = 1 + }; + + InvokeWrapper(binder.Name, INVOKEKIND.INVOKE_PROPERTYPUT, dispParams); + + return true; + } + + public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object? result) + { + var index = (int)indexes[0]; + + var dispParams = new DispParams + { + rgvarg = [new Variant(index)], + rgdispidNamedArgs = 0, + cArgs = 1, + cNamedArgs = 0 + }; + + result = InvokeWrapper("Item", INVOKEKIND.INVOKE_PROPERTYGET, dispParams); + + return true; + } + + public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) + { + throw new NotImplementedException(); + } + + public override bool TryInvokeMember( + InvokeMemberBinder binder, + object[] args, + out object result + ) + { + //DispParams dispParams = new(); + + Variant[] a = new Variant[args.Length]; + for (int i = 0; i < args.Length; ++i) + a[i] = new Variant(args[i]); + + var dispParams = new DispParams + { + rgvarg = a, + rgdispidNamedArgs = 0, + cArgs = a.Length, + cNamedArgs = 0 + }; + + result = InvokeWrapper(binder.Name, INVOKEKIND.INVOKE_FUNC, dispParams); + + return true; + } + + public object InvokeMember( + string name, + object[] args +) + { + //DispParams dispParams = new(); + + Variant[] a = new Variant[args.Length]; + for (int i = 0; i < args.Length; ++i) + { + object? o = args[i].GetType().IsEnum ? (int)args[i] : args[i]; + if (o == Type.Missing) + o = null; + + System.Diagnostics.Trace.WriteLine("[InvokeMember] " + name + " " + o?.GetType().ToString()); + a[i] = new Variant(o); + } + + var dispParams = new DispParams + { + rgvarg = a, + rgdispidNamedArgs = 0, + cArgs = a.Length, + cNamedArgs = 0 + }; + + return InvokeWrapper(name, INVOKEKIND.INVOKE_FUNC, dispParams); + } + + public object InvokeWrapper(string propName, INVOKEKIND kind, DispParams dispParams) + { + var dispIds = GetDispIDs(propName); + + ExcepInfo pExcepInfo = new(); + Variant pVarResult = new(); + uint puArgErr = 0; + + var hr = _interfacePtr.Invoke( + dispIds[0], + emptyGuid, + LOCALE_USER_DEFAULT, + kind, + ref dispParams, + ref pVarResult, + ref pExcepInfo, + ref puArgErr + ); + + Marshal.ThrowExceptionForHR(hr); + + // Found an IDispatch object - swap current instance + if (pVarResult.Value is IDispatch interfacePtr) + { + return new ExcelObject(interfacePtr); + } + + return pVarResult.Value; + } + + private int[] GetDispIDs(string propName) + { + var names = new string[] { propName }; + + var dispIds = new int[names.Length]; + var hr = _interfacePtr.GetIDsOfNames( + ref emptyGuid, + names, + (uint)names.Length, + LOCALE_USER_DEFAULT, + dispIds + ); + + if (hr < 0) + { + Marshal.ThrowExceptionForHR(hr); + } + + if (_verbose) + { + for (int i = 0; i < names.Length; i++) + Console.WriteLine($"{names[i]}: {dispIds[i]}"); + } + + return dispIds; + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ICommandBarControl.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ICommandBarControl.cs new file mode 100644 index 00000000..436e563b --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ICommandBarControl.cs @@ -0,0 +1,33 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; +using System.Runtime.InteropServices.Marshalling; +using Managed = Addin.Types.Managed; +using Marshalling = Addin.Types.Marshalling; + +namespace Addin.ComApi; + +[GeneratedComInterface] +[Guid("000C030E-0000-0000-C000-000000000046")] +public partial interface ICommandBarButton +{ +} + +[GeneratedComInterface] +[Guid("000C030A-0000-0000-C000-000000000046")] +public partial interface ICommandBarPopup +{ +} + +[GeneratedComInterface] +[Guid("000C030C-0000-0000-C000-000000000046")] +public partial interface ICommandBarComboBox +{ +} + +//[GeneratedComInterface] +//[Guid("000C0306-0000-0000-C000-000000000046")] +//public partial interface ICommandBarControls +//{ +// [PreserveSig] +// object Add(object Type, object Id, object Parameter, object Before, object Temporary); +//} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/IDispatch.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/IDispatch.cs new file mode 100644 index 00000000..c8998601 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/IDispatch.cs @@ -0,0 +1,39 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; +using System.Runtime.InteropServices.Marshalling; +using Managed = Addin.Types.Managed; +using Marshalling = Addin.Types.Marshalling; + +namespace Addin.ComApi; + +[GeneratedComInterface] +[Guid("00020400-0000-0000-C000-000000000046")] // The IID for IDispatch +public partial interface IDispatch +{ + [PreserveSig] + int GetTypeInfoCount(out uint pctinfo); + + [PreserveSig] + int GetTypeInfo(uint iTInfo, uint lcid, out nint ppTInfo); + + [PreserveSig] + int GetIDsOfNames( + ref Guid riid, + [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] rgszNames, + uint cNames, + uint lcid, + [MarshalAs(UnmanagedType.LPArray)] int[] rgDispId + ); + + [PreserveSig] + int Invoke( + int dispIdMember, + Guid riid, + uint lcid, + INVOKEKIND wFlags, + [MarshalUsing(typeof(Marshalling.DispParams))] ref Managed.DispParams pDispParams, + [MarshalUsing(typeof(Marshalling.Variant))] ref Managed.Variant pVarResult, + [MarshalUsing(typeof(Marshalling.ExcepInfo))] ref Managed.ExcepInfo pExcepInfo, + ref uint puArgErr + ); +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Excel.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Excel.cs new file mode 100644 index 00000000..a2e2f2f1 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Excel.cs @@ -0,0 +1,115 @@ +using Addin.ComApi; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using System.Text; +using System.Threading.Tasks; + +namespace ExcelDna.COMWrappers.NativeAOT +{ + internal class Excel + { + public static object? GetApplicationFromWindow(IntPtr hWndMain) + { + object? result = null; + StringBuilder cname = new StringBuilder(256); + + EnumChildWindows(hWndMain, delegate (IntPtr hWndEnum, IntPtr param) + { + // Check the window class + GetClassNameW(hWndEnum, cname, cname.Capacity); + + System.Diagnostics.Trace.WriteLine("[GetApplicationFromWindow cname ]" + cname.ToString()); + + + if (cname.ToString() != "EXCEL7") + // Not a workbook window, continue enumerating + return true; + + System.Diagnostics.Trace.WriteLine("[GetApplicationFromWindow got EXCEL7]"); + + + IntPtr pUnk = IntPtr.Zero; + int hr = AccessibleObjectFromWindow(hWndEnum, OBJID_NATIVEOM, IID_IDispatchBytes, ref pUnk); + if (hr != 0) + { + // Window does not implement the IID, continue enumerating + return true; + } + + System.Diagnostics.Trace.WriteLine("[GetApplicationFromWindow got pUnk]"); + + // Marshal to .NET, then call .Application + //object obj = Marshal.GetObjectForIUnknown(pUnk); + //Console.WriteLine("GetApplicationFromWindow GetObjectForIUnknown"); + + ComWrappers cw = new StrategyBasedComWrappers(); + //object obj = cw.GetOrCreateObjectForComInstance(pUnk, CreateObjectFlags.None); + //ComObject co = obj; + + //var t = obj.GetType(); + IDispatch foo = (IDispatch)cw.GetOrCreateObjectForComInstance(pUnk, CreateObjectFlags.None); + //foo. + //IntPtr app = foo.get_Application2xx(); + + //hr = foo.GetTypeInfoCount(out uint tcount); + + //const int LcidUsEnglish = 0x0409; + //string[] names = new string[1]; + //int[] ids = new int[1]; + //names[0] = "Application"; + //Guid g = Guid.Empty; + //hr = foo.GetIDsOfNames(ref g, names, 1, LcidUsEnglish, ids); + + //int[] i1 = new int[4]; + //IntPtr i2 = 0; + //hr = foo.Invoke(ids[0], ref g, LcidUsEnglish, 2, i1, out IntPtr pVarResult, ref i2, out uint perr); + + var excelWindowWrapper = new ExcelObject(foo); + + var app = excelWindowWrapper.GetProperty("Application"); + if (app is ExcelObject excelObject) + result = excelObject._interfacePtr; + else + result = app; + + //dynamic dapp = app; + //var commandBars = dapp.CommandBars; + //var worksheetBar = commandBars[1]; + //var controls = worksheetBar.Controls; + + //string menuName = "ConsoleApp1 Menu"; + //var menu = controls.AddPopup(menuName); + //menu.Caption = menuName; + + //Console.WriteLine("GetApplicationFromWindow GetOrCreateObjectForComInstance"); + + + return result == null; + }, IntPtr.Zero); + + System.Diagnostics.Trace.WriteLine("[GetApplicationFromWindow result]" + result?.GetType().ToString()); + + return result; + } + + private delegate bool EnumWindowsCallback(IntPtr hwnd, /*ref*/ IntPtr param); + + [DllImport("user32.dll")] + private static extern bool EnumChildWindows(IntPtr hWndParent, EnumWindowsCallback callback, /*ref*/ IntPtr param); + + [DllImport("user32.dll")] + private static extern int GetClassNameW(IntPtr hwnd, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder buf, int nMaxCount); + + [DllImport("Oleacc.dll")] + private static extern int AccessibleObjectFromWindow( + IntPtr hwnd, uint dwObjectID, byte[] riid, + ref IntPtr ptr /*ppUnk*/); + + private const uint OBJID_NATIVEOM = 0xFFFFFFF0; + + private static readonly byte[] IID_IDispatchBytes = new Guid("{00020400-0000-0000-C000-000000000046}").ToByteArray(); + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ExcelDna.COMWrappers.NativeAOT.csproj b/Source/ExcelDna.COMWrappers.NativeAOT/ExcelDna.COMWrappers.NativeAOT.csproj new file mode 100644 index 00000000..de7bbaec --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ExcelDna.COMWrappers.NativeAOT.csproj @@ -0,0 +1,14 @@ + + + + net8.0-windows + enable + enable + true + + + + + + + diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/OpenWindowGetter.cs b/Source/ExcelDna.COMWrappers.NativeAOT/OpenWindowGetter.cs new file mode 100644 index 00000000..9e67d244 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/OpenWindowGetter.cs @@ -0,0 +1,53 @@ +using System.Runtime.InteropServices; +using System.Text; +using HWND = System.IntPtr; + +namespace ExcelDna.COMWrappers.NativeAOT +{ + /// Contains functionality to get all the open windows. + public static class OpenWindowGetter + { + /// Returns a dictionary that contains the handle and title of all the open windows. + /// A dictionary that contains the handle and title of all the open windows. + public static IDictionary GetOpenWindows() + { + HWND shellWindow = GetShellWindow(); + Dictionary windows = new Dictionary(); + + EnumWindows(delegate (HWND hWnd, int lParam) + { + if (hWnd == shellWindow) return true; + if (!IsWindowVisible(hWnd)) return true; + + int length = GetWindowTextLength(hWnd); + if (length == 0) return true; + + StringBuilder builder = new StringBuilder(length); + GetWindowText(hWnd, builder, length + 1); + + windows[hWnd] = builder.ToString(); + return true; + + }, 0); + + return windows; + } + + private delegate bool EnumWindowsProc(HWND hWnd, int lParam); + + [DllImport("USER32.DLL")] + private static extern bool EnumWindows(EnumWindowsProc enumFunc, int lParam); + + [DllImport("USER32.DLL")] + private static extern int GetWindowText(HWND hWnd, StringBuilder lpString, int nMaxCount); + + [DllImport("USER32.DLL")] + private static extern int GetWindowTextLength(HWND hWnd); + + [DllImport("USER32.DLL")] + private static extern bool IsWindowVisible(HWND hWnd); + + [DllImport("USER32.DLL")] + private static extern IntPtr GetShellWindow(); + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs b/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs new file mode 100644 index 00000000..9a2f11b4 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs @@ -0,0 +1,52 @@ +using Addin.ComApi; +using ExcelDna.ComInterop; + +namespace ExcelDna.COMWrappers.NativeAOT +{ + public class TypeAdapter : IType + { + public object GetProperty(string name, object comObject) + { + var excelWindowWrapper = new ExcelObject(comObject as IDispatch); + object? result = excelWindowWrapper.GetProperty(name); + if (result is ExcelObject excelObject) + return excelObject._interfacePtr; + + return result!; + } + + public object GetIndex(int i, object comObject) + { + var excelWindowWrapper = new ExcelObject(comObject as IDispatch); + excelWindowWrapper.TryGetIndex(null, new object[] { i }, out object? result); + if (result is ExcelObject excelObject) + return excelObject._interfacePtr; + + return result!; + } + + public bool Is(ref Guid guid, object comObject) + { + if (guid == new Guid("000C030E-0000-0000-C000-000000000046")) + return comObject is ICommandBarButton; + + if (guid == new Guid("000C030A-0000-0000-C000-000000000046")) + return comObject is ICommandBarPopup; + + if (guid == new Guid("000C030C-0000-0000-C000-000000000046")) + return comObject is ICommandBarComboBox; + + throw new NotImplementedException(); + } + + public object Invoke(string name, object[] args, object comObject) + { + var excelWindowWrapper = new ExcelObject(comObject as IDispatch); + object? result = excelWindowWrapper.InvokeMember(name, args); + if (result is ExcelObject excelObject) + return excelObject._interfacePtr; + + return result!; + } + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/DispParams.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/DispParams.cs new file mode 100644 index 00000000..19fd236c --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/DispParams.cs @@ -0,0 +1,9 @@ +namespace Addin.Types.Managed; + +public struct DispParams +{ + public int cArgs; + public int cNamedArgs; + public int rgdispidNamedArgs; + public Variant[] rgvarg; +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/ExcepInfo.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/ExcepInfo.cs new file mode 100644 index 00000000..77f3e822 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/ExcepInfo.cs @@ -0,0 +1,53 @@ +namespace Addin.Types.Managed; + +public struct ExcepInfo +{ + // + // Summary: + // Describes the error intended for the customer. + public string bstrDescription; + + // + // Summary: + // Contains the fully-qualified drive, path, and file name of a Help file that contains + // more information about the error. + public string bstrHelpFile; + + // + // Summary: + // Indicates the name of the source of the exception. Typically, this is an application + // name. + public string bstrSource; + + // + // Summary: + // Indicates the Help context ID of the topic within the Help file. + public int dwHelpContext; + + // + // Summary: + // Represents a pointer to a function that takes an System.Runtime.InteropServices.EXCEPINFO + // structure as an argument and returns an HRESULT value. If deferred fill-in is + // not desired, this field is set to null. + public nint pfnDeferredFillIn; + + // + // Summary: + // This field is reserved; it must be set to null. + public nint pvReserved; + + // + // Summary: + // A return value describing the error. + public int scode; + + // + // Summary: + // Represents an error code identifying the error. + public short wCode; + + // + // Summary: + // This field is reserved; it must be set to 0. + public short wReserved; +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/Variant.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/Variant.cs new file mode 100644 index 00000000..f0c3bafa --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/Variant.cs @@ -0,0 +1,11 @@ +namespace Addin.Types.Managed; + +public struct Variant +{ + public Variant(object? value) + { + Value = value; + } + + public object? Value { get; set; } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/XlOper.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/XlOper.cs new file mode 100644 index 00000000..8ce227d9 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/XlOper.cs @@ -0,0 +1,60 @@ +namespace Addin.Types.Managed; + +using Addin.Types.Unmanaged; +using System.Runtime.InteropServices; +using static Addin.Types.Unmanaged.ExcelConstants; + +public class XlOper +{ + xloper12 _instance; + + public XlOper() + { + _instance = new(); + } + + public XlOper(string str) + { + // Calculate sizes + var strLen = str.Length + 1; + var charLen = Marshal.SizeOf(str[0]); + var byteCount = charLen * strLen; + + // Create byte array, with the length stored in the first char and the string contents on the rest + var bytes = new char[strLen]; + bytes[0] = (char)(strLen - 1); + Buffer.BlockCopy(str.ToCharArray(), 0, bytes, charLen, byteCount - charLen); + + // Convert to unmanaged bytes + var strPtr = Marshal.AllocHGlobal(byteCount); + Marshal.Copy(bytes, 0, strPtr, strLen); + + // Add to XlOper structure + xloper12 lpx = new() { xltype = xltypeStr }; + lpx.val.str = strPtr; + _instance = lpx; + } + + public XlOper(nint ptr) + { + _instance = Marshal.PtrToStructure(ptr); + } + + public override string? ToString() + { + if (_instance.xltype != xltypeStr) + throw new NotSupportedException(); + var str = Marshal.PtrToStringUni(_instance.val.str); + var bytes = str?.ToCharArray().Skip(1).ToArray(); + return new string(bytes); + } + + public nint ToPtr() + { + var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(_instance)); + + Marshal.StructureToPtr(_instance, ptr, false); + + return ptr; + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Array.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Array.cs new file mode 100644 index 00000000..ccd50a4a --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Array.cs @@ -0,0 +1,31 @@ +using System.Runtime.InteropServices; + +namespace Addin.Types.Marshalling; + +public static class Array +{ + public static nint ArrayToPtr(T[] str) + { + var size = Marshal.SizeOf(); + var len = str.Length; + var ptrs = new nint[str.Length]; + var basePtr = Marshal.AllocHGlobal(size * len); + for (int i = 0; i < len; ++i) + { + ptrs[i] = nint.Add(basePtr, i * size); + Marshal.StructureToPtr(str[i], ptrs[i], false); + } + return basePtr; + } + + public static T[] PtrToArray(nint str, int len) + { + var size = Marshal.SizeOf(); + var ret = new T[len]; + for (int i = 0; i < len; ++i) + { + ret[i] = Marshal.PtrToStructure(nint.Add(str, i * size)); + } + return ret; + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/DispParams.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/DispParams.cs new file mode 100644 index 00000000..f799f926 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/DispParams.cs @@ -0,0 +1,35 @@ +using System.Runtime.InteropServices.Marshalling; + +namespace Addin.Types.Marshalling; + +[CustomMarshaller(typeof(Managed.DispParams), MarshalMode.Default, typeof(DispParams))] +public static class DispParams +{ + public static unsafe Unmanaged.DispParams ConvertToUnmanaged(Managed.DispParams managed) + { + return new Unmanaged.DispParams + { + cArgs = managed.cArgs, + cNamedArgs = managed.cNamedArgs, + rgdispidNamedArgs = &managed.rgdispidNamedArgs, + rgvarg = + managed.rgvarg != null + ? Array.ArrayToPtr(managed.rgvarg.Select(Variant.ConvertToUnmanaged).ToArray()) + : nint.Zero + }; + } + + public static unsafe Managed.DispParams ConvertToManaged(Unmanaged.DispParams unmanaged) + { + return new Managed.DispParams + { + cArgs = unmanaged.cArgs, + cNamedArgs = unmanaged.cNamedArgs, + rgdispidNamedArgs = *unmanaged.rgdispidNamedArgs, + rgvarg = Array + .PtrToArray(unmanaged.rgvarg, unmanaged.cArgs) + .Select(Variant.ConvertToManaged) + .ToArray(), + }; + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/ExcepInfo.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/ExcepInfo.cs new file mode 100644 index 00000000..5eebbe1b --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/ExcepInfo.cs @@ -0,0 +1,45 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Addin.Types.Marshalling; + +[CustomMarshaller(typeof(Managed.ExcepInfo), MarshalMode.Default, typeof(ExcepInfo))] +public static class ExcepInfo +{ + public static Unmanaged.ExcepInfo ConvertToUnmanaged(Managed.ExcepInfo managed) + { + return new Unmanaged.ExcepInfo + { + bstrDescription = Marshal.StringToBSTR(managed.bstrDescription), + bstrHelpFile = Marshal.StringToBSTR(managed.bstrHelpFile), + bstrSource = Marshal.StringToBSTR(managed.bstrSource), + dwHelpContext = managed.dwHelpContext, + pfnDeferredFillIn = managed.pfnDeferredFillIn, + pvReserved = managed.pvReserved, + scode = managed.scode, + wCode = managed.wCode, + wReserved = managed.wReserved, + }; + } + + public static Managed.ExcepInfo ConvertToManaged(Unmanaged.ExcepInfo unmanaged) + { + return new Managed.ExcepInfo + { + bstrDescription = + unmanaged.bstrDescription != 0 + ? Marshal.PtrToStringBSTR(unmanaged.bstrDescription) + : "", + bstrHelpFile = + unmanaged.bstrHelpFile != 0 ? Marshal.PtrToStringBSTR(unmanaged.bstrHelpFile) : "", + bstrSource = + unmanaged.bstrSource != 0 ? Marshal.PtrToStringBSTR(unmanaged.bstrSource) : "", + dwHelpContext = unmanaged.dwHelpContext, + pfnDeferredFillIn = unmanaged.pfnDeferredFillIn, + pvReserved = unmanaged.pvReserved, + scode = unmanaged.scode, + wCode = unmanaged.wCode, + wReserved = unmanaged.wReserved, + }; + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Variant.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Variant.cs new file mode 100644 index 00000000..68f59da3 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Variant.cs @@ -0,0 +1,60 @@ +using Addin.ComApi; +using Addin.Types.Unmanaged; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Addin.Types.Marshalling; + +[CustomMarshaller(typeof(Managed.Variant), MarshalMode.Default, typeof(Variant))] +public static class Variant +{ + public static Unmanaged.Variant ConvertToUnmanaged(Managed.Variant managed) + { + return managed.Value switch + { + bool boolVal + => new Unmanaged.Variant + { + vt = (ushort)VariantType.VT_BOOL, + boolVal = (short)( + boolVal ? VariantBool.VARIANT_TRUE : VariantBool.VARIANT_FALSE + ), + }, + int lVal => new Unmanaged.Variant { vt = (ushort)VariantType.VT_I4, lVal = lVal, }, + string bstrVal + => new Unmanaged.Variant + { + vt = (ushort)VariantType.VT_BSTR, + bstrVal = Marshal.StringToBSTR(bstrVal), + }, + null => new Unmanaged.Variant { }, + _ => + throw new NotImplementedException(managed.Value.GetType().ToString()) + , + }; + } + + public static unsafe Managed.Variant ConvertToManaged(Unmanaged.Variant unmanaged) + { + return (VariantType)unmanaged.vt switch + { + VariantType.VT_BOOL + => new Managed.Variant + { + Value = unmanaged.boolVal == (short)VariantBool.VARIANT_TRUE, + }, + VariantType.VT_I4 => new Managed.Variant { Value = unmanaged.lVal, }, + VariantType.VT_BSTR + => new Managed.Variant { Value = Marshal.PtrToStringBSTR(unmanaged.bstrVal), }, + VariantType.VT_DISPATCH + => new Managed.Variant + { + Value = ComInterfaceMarshaller.ConvertToManaged( + (void*)unmanaged.pdispVal + ), + }, + VariantType.VT_EMPTY => new Managed.Variant { }, + _ => throw new NotImplementedException(), + }; + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ClsCtx.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ClsCtx.cs new file mode 100644 index 00000000..ea4d45f6 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ClsCtx.cs @@ -0,0 +1,33 @@ +namespace Addin.Types.Unmanaged; + +public enum ClsCtx : uint +{ + CLSCTX_INPROC_SERVER = 0x1, + CLSCTX_INPROC_HANDLER = 0x2, + CLSCTX_LOCAL_SERVER = 0x4, + CLSCTX_INPROC_SERVER16 = 0x8, + CLSCTX_REMOTE_SERVER = 0x10, + CLSCTX_INPROC_HANDLER16 = 0x20, + CLSCTX_RESERVED1 = 0x40, + CLSCTX_RESERVED2 = 0x80, + CLSCTX_RESERVED3 = 0x100, + CLSCTX_RESERVED4 = 0x200, + CLSCTX_NO_CODE_DOWNLOAD = 0x400, + CLSCTX_RESERVED5 = 0x800, + CLSCTX_NO_CUSTOM_MARSHAL = 0x1000, + CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000, + CLSCTX_NO_FAILURE_LOG = 0x4000, + CLSCTX_DISABLE_AAA = 0x8000, + CLSCTX_ENABLE_AAA = 0x10000, + CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000, + CLSCTX_ACTIVATE_X86_SERVER = 0x40000, + CLSCTX_ACTIVATE_32_BIT_SERVER = CLSCTX_ACTIVATE_X86_SERVER, + CLSCTX_ACTIVATE_64_BIT_SERVER = 0x80000, + CLSCTX_ENABLE_CLOAKING = 0x100000, + CLSCTX_APPCONTAINER = 0x400000, + CLSCTX_ACTIVATE_AAA_AS_IU = 0x800000, + CLSCTX_RESERVED6 = 0x1000000, + CLSCTX_ACTIVATE_ARM32_SERVER = 0x2000000, + CLSCTX_ALLOW_LOWER_TRUST_REGISTRATION = 0x4000000, + CLSCTX_PS_DLL = 0x80000000 +}; diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ComConstants.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ComConstants.cs new file mode 100644 index 00000000..9c436bfe --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ComConstants.cs @@ -0,0 +1,9 @@ +namespace Addin.Types.Unmanaged; + +public class ComConstants +{ + public const int LOCALE_SYSTEM_DEFAULT = 0x0800; + public const int LOCALE_USER_DEFAULT = 0x0400; + public const int DISPID_PROPERTYPUT = -3; + public const uint OBJID_NATIVEOM = 0xFFFFFFF0; +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/DispParams.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/DispParams.cs new file mode 100644 index 00000000..17942587 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/DispParams.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace Addin.Types.Unmanaged; + +[StructLayout(LayoutKind.Sequential)] +public unsafe struct DispParams +{ + public nint rgvarg; + public int* rgdispidNamedArgs; + public int cArgs; + public int cNamedArgs; +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ExcelConstants.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ExcelConstants.cs new file mode 100644 index 00000000..1ca0336a --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ExcelConstants.cs @@ -0,0 +1,100 @@ +namespace Addin.Types.Unmanaged; + +public static class ExcelConstants +{ + // Function number bits + public static readonly int xlCommand = 0x8000; + public static readonly int xlSpecial = 0x4000; + public static readonly int xlIntl = 0x2000; + public static readonly int xlPrompt = 0x1000; + + // Auxiliary function numbers + // These functions are available only from the C API, + // not from the Excel macro language. + public static readonly int xlFree = 0 | xlSpecial; + public static readonly int xlStack = 1 | xlSpecial; + public static readonly int xlCoerce = 2 | xlSpecial; + public static readonly int xlSet = 3 | xlSpecial; + public static readonly int xlSheetId = 4 | xlSpecial; + public static readonly int xlSheetNm = 5 | xlSpecial; + public static readonly int xlAbort = 6 | xlSpecial; + + // Returns application's hinstance as an integer value, supported on 32-bit platform only + public static readonly int xlGetInst = 7 | xlSpecial; + public static readonly int xlGetHwnd = 8 | xlSpecial; + public static readonly int xlGetName = 9 | xlSpecial; + public static readonly int xlEnableXLMsgs = 10 | xlSpecial; + public static readonly int xlDisableXLMsgs = 11 | xlSpecial; + public static readonly int xlDefineBinaryName = 12 | xlSpecial; + public static readonly int xlGetBinaryName = 13 | xlSpecial; + + // GetFooInfo are valid only for calls to LPenHelper + public static readonly int xlGetFmlaInfo = 14 | xlSpecial; + public static readonly int xlGetMouseInfo = 15 | xlSpecial; + + // Set return value from an asynchronous function call + public static readonly int xlAsyncReturn = 16 | xlSpecial; + + // Register an XLL event + public static readonly int xlEventRegister = 17 | xlSpecial; + + // Returns true if running on Compute Cluster + public static readonly int xlRunningOnCluster = 18 | xlSpecial; + + // Returns application's hinstance as a handle, supported on both 32-bit and 64-bit platforms + public static readonly int xlGetInstPtr = 19 | xlSpecial; + + public static readonly int xlfRegister = 149; + + public static readonly int xltypeNum = 0x0001; + public static readonly int xltypeStr = 0x0002; + public static readonly int xltypeBool = 0x0004; + public static readonly int xltypeRef = 0x0008; + public static readonly int xltypeErr = 0x0010; + public static readonly int xltypeFlow = 0x0020; + public static readonly int xltypeMulti = 0x0040; + public static readonly int xltypeMissing = 0x0080; + public static readonly int xltypeNil = 0x0100; + public static readonly int xltypeSRef = 0x0400; + public static readonly int xltypeInt = 0x0800; + + public static readonly int xlbitXLFree = 0x1000; + public static readonly int xlbitDLLFree = 0x4000; + + public static readonly int xltypeBigData = xltypeStr | xltypeInt; + + // Error codes + // Used for val.err field of XLOPER and XLOPER12 structures + // when constructing error XLOPERs and XLOPER12s + public static readonly int xlerrNull = 0; + public static readonly int xlerrDiv0 = 7; + public static readonly int xlerrValue = 15; + public static readonly int xlerrRef = 23; + public static readonly int xlerrName = 29; + public static readonly int xlerrNum = 36; + public static readonly int xlerrNA = 42; + public static readonly int xlerrGettingData = 43; + + // Flow data types + // Used for val.flow.xlflow field of XLOPER and XLOPER12 structures + // when constructing flow-control XLOPERs and XLOPER12s + public static readonly int xlflowHalt = 1; + public static readonly int xlflowGoto = 2; + public static readonly int xlflowRestart = 8; + public static readonly int xlflowPause = 16; + public static readonly int xlflowResume = 64; + + // Return codes + // These values can be returned from Excel4(), Excel4v(), Excel12() or Excel12v(). + public static readonly int xlretSuccess = 0; // success + public static readonly int xlretAbort = 1; // macro halted + public static readonly int xlretInvXlfn = 2; // invalid function number + public static readonly int xlretInvCount = 4; // invalid number of arguments + public static readonly int xlretInvXloper = 8; // invalid OPER structure + public static readonly int xlretStackOvfl = 16; // stack overflow + public static readonly int xlretFailed = 32; // command failed + public static readonly int xlretUncalced = 64; // uncalced cell + public static readonly int xlretNotThreadSafe = 128; // not allowed during multi-threaded calc + public static readonly int xlretInvAsynchronousContext = 256; // invalid asynchronous function handle + public static readonly int xlretNotClusterSafe = 512; // not supported on cluster +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ExcepInfo.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ExcepInfo.cs new file mode 100644 index 00000000..efa48d96 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ExcepInfo.cs @@ -0,0 +1,17 @@ +using System.Runtime.InteropServices; + +namespace Addin.Types.Unmanaged; + +[StructLayout(LayoutKind.Sequential)] +public struct ExcepInfo +{ + public short wCode; + public short wReserved; + public nint bstrSource; + public nint bstrDescription; + public nint bstrHelpFile; + public int dwHelpContext; + public nint pvReserved; + public nint pfnDeferredFillIn; + public int scode; +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/Variant.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/Variant.cs new file mode 100644 index 00000000..c489c3f3 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/Variant.cs @@ -0,0 +1,208 @@ +using System.Runtime.InteropServices; + +namespace Addin.Types.Unmanaged; + +[StructLayout(LayoutKind.Explicit)] +public struct Variant +{ + [FieldOffset(0)] + public DECIMAL decVal; + + [FieldOffset(0)] + public ushort vt; + + [FieldOffset(2)] + public ushort wReserved1; + + [FieldOffset(4)] + public ushort wReserved2; + + [FieldOffset(6)] + public ushort wReserved3; + + [FieldOffset(8)] + public long llVal; + + [FieldOffset(8)] + public int lVal; + + [FieldOffset(8)] + public byte bVal; + + [FieldOffset(8)] + public short iVal; + + [FieldOffset(8)] + public float fltVal; + + [FieldOffset(8)] + public double dblVal; + + [FieldOffset(8)] + public short boolVal; + + [FieldOffset(8)] + public short __OBSOLETE__VARIANT_BOOL; + + [FieldOffset(8)] + public int scode; + + [FieldOffset(8)] + public CY cyVal; + + [FieldOffset(8)] + public double date; + + [FieldOffset(8)] + public nint bstrVal; + + [FieldOffset(8)] + public nint punkVal; + + [FieldOffset(8)] + public nint pdispVal; + + [FieldOffset(8)] + public nint parray; + + [FieldOffset(8)] + public nint pbVal; + + [FieldOffset(8)] + public nint piVal; + + [FieldOffset(8)] + public nint plVal; + + [FieldOffset(8)] + public nint pllVal; + + [FieldOffset(8)] + public nint pfltVal; + + [FieldOffset(8)] + public nint pdblVal; + + [FieldOffset(8)] + public nint pboolVal; + + [FieldOffset(8)] + public nint __OBSOLETE__VARIANT_PBOOL; + + [FieldOffset(8)] + public nint pscode; + + [FieldOffset(8)] + public nint pcyVal; + + [FieldOffset(8)] + public nint pdate; + + [FieldOffset(8)] + public nint pbstrVal; + + [FieldOffset(8)] + public nint ppunkVal; + + [FieldOffset(8)] + public nint ppdispVal; + + [FieldOffset(8)] + public nint pparray; + + [FieldOffset(8)] + public nint pvarVal; + + [FieldOffset(8)] + public nint byref; + + [FieldOffset(8)] + public sbyte cVal; + + [FieldOffset(8)] + public ushort uiVal; + + [FieldOffset(8)] + public uint ulVal; + + [FieldOffset(8)] + public ulong ullVal; + + [FieldOffset(8)] + public int intVal; + + [FieldOffset(8)] + public uint uintVal; + + [FieldOffset(8)] + public nint pdecVal; + + [FieldOffset(8)] + public nint pcVal; + + [FieldOffset(8)] + public nint puiVal; + + [FieldOffset(8)] + public nint pulVal; + + [FieldOffset(8)] + public nint pullVal; + + [FieldOffset(8)] + public nint pintVal; + + [FieldOffset(8)] + public nint puintVal; + + [FieldOffset(8)] + public __tagBRECORD __tagBRECORD; +} + +[StructLayout(LayoutKind.Explicit)] +public struct CY +{ + [FieldOffset(0)] + public uint Lo; + + [FieldOffset(4)] + public int Hi; + + [FieldOffset(0)] + public long int64; +} + +[StructLayout(LayoutKind.Sequential)] +public struct __tagBRECORD +{ + public nint pvRecord; + public nint pRecInfo; +} + +[StructLayout(LayoutKind.Explicit)] +public struct DECIMAL +{ + [FieldOffset(0)] + public ushort wReserved; + + [FieldOffset(2)] + public ushort signscale; + + [FieldOffset(2)] + public byte scale; + + [FieldOffset(3)] + public byte sign; + + [FieldOffset(4)] + public uint Hi32; + + [FieldOffset(8)] + public ulong Lo64; + + [FieldOffset(8)] + public uint Lo32; + + [FieldOffset(12)] + public uint Mid32; +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/VariantBool.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/VariantBool.cs new file mode 100644 index 00000000..1f4a2688 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/VariantBool.cs @@ -0,0 +1,7 @@ +namespace Addin.Types.Unmanaged; + +public enum VariantBool : short +{ + VARIANT_FALSE = 0, + VARIANT_TRUE = -1 +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/VariantType.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/VariantType.cs new file mode 100644 index 00000000..4fa206ac --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/VariantType.cs @@ -0,0 +1,57 @@ +namespace Addin.Types.Unmanaged; + +public enum VariantType : ushort +{ + VT_EMPTY = 0, + VT_NULL = 1, + VT_I2 = 2, + VT_I4 = 3, + VT_R4 = 4, + VT_R8 = 5, + VT_CY = 6, + VT_DATE = 7, + VT_BSTR = 8, + VT_DISPATCH = 9, + VT_ERROR = 10, + VT_BOOL = 11, + VT_VARIANT = 12, + VT_UNKNOWN = 13, + VT_DECIMAL = 14, + VT_I1 = 16, + VT_UI1 = 17, + VT_UI2 = 18, + VT_UI4 = 19, + VT_I8 = 20, + VT_UI8 = 21, + VT_INT = 22, + VT_UINT = 23, + VT_VOID = 24, + VT_HRESULT = 25, + VT_PTR = 26, + VT_SAFEARRAY = 27, + VT_CARRAY = 28, + VT_USERDEFINED = 29, + VT_LPSTR = 30, + VT_LPWSTR = 31, + VT_RECORD = 36, + VT_INT_PTR = 37, + VT_UINT_PTR = 38, + VT_FILETIME = 64, + VT_BLOB = 65, + VT_STREAM = 66, + VT_STORAGE = 67, + VT_STREAMED_OBJECT = 68, + VT_STORED_OBJECT = 69, + VT_BLOB_OBJECT = 70, + VT_CF = 71, + VT_CLSID = 72, + VT_VERSIONED_STREAM = 73, + VT_BSTR_BLOB = 0xfff, + VT_VECTOR = 0x1000, + VT_ARRAY = 0x2000, + VT_BYREF = 0x4000, + VT_RESERVED = 0x8000, + VT_X = 0xffff, + VT_Y = 0xfff, + VT_TYPEMASK = 0xfff +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/XlOper12.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/XlOper12.cs new file mode 100644 index 00000000..7edba2f8 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/XlOper12.cs @@ -0,0 +1,178 @@ +using System.Runtime.InteropServices; + +namespace Addin.Types.Unmanaged; + +[StructLayout(LayoutKind.Sequential)] +public struct xlref12 +{ + /// RW->INT32->int + public int rwFirst; + + /// RW->INT32->int + public int rwLast; + + /// COL->INT32->int + public int colFirst; + + /// COL->INT32->int + public int colLast; +} + +[StructLayout(LayoutKind.Sequential)] +public struct xmlref12 +{ + /// WORD->short + public short count; + + /// XLREF12[1] + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1, ArraySubType = UnmanagedType.Struct)] + public xlref12[] reftbl; +} + +[StructLayout(LayoutKind.Sequential)] +public struct FP12 +{ + /// INT32->int + public int rows; + + /// INT32->int + public int columns; + + /// double[1] + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1, ArraySubType = UnmanagedType.R8)] + public double[] array; +} + +[StructLayout(LayoutKind.Sequential)] +public struct sref +{ + /// WORD->short + public short count; + + /// XLREF12->xlref12 + public xlref12 @ref; +} + +[StructLayout(LayoutKind.Sequential)] +public struct mref +{ + /// XLMREF12* + public nint lpmref; + + /// IDSHEET->DWORD_PTR->ULONG_PTR->int + public int idSheet; +} + +[StructLayout(LayoutKind.Sequential)] +public struct array +{ + /// xloper12* + public nint lparray; + + /// RW->INT32->int + public int rows; + + /// COL->INT32->int + public int columns; +} + +[StructLayout(LayoutKind.Explicit)] +public struct valflow +{ + /// int + [FieldOffset(0)] + public int level; + + /// int + [FieldOffset(0)] + public int tbctrl; + + /// IDSHEET->DWORD_PTR->ULONG_PTR->int + [FieldOffset(0)] + public int idSheet; +} + +[StructLayout(LayoutKind.Sequential)] +public struct flow +{ + public valflow valflow; + + /// RW->INT32->int + public int rw; + + /// COL->INT32->int + public int col; + + /// BYTE->char + public byte xlflow; +} + +[StructLayout(LayoutKind.Explicit)] +public struct h +{ + /// BYTE* + [FieldOffset(0)] + public nint lpbData; + + /// HANDLE->void* + [FieldOffset(0)] + public nint hdata; +} + +[StructLayout(LayoutKind.Sequential)] +public struct bigdata +{ + public h h; + + /// int + public int cbData; +} + +[StructLayout(LayoutKind.Explicit)] +public struct val +{ + /// double + [FieldOffset(0)] + public double num; + + /// XCHAR* + [FieldOffset(0)] + public nint str; + + /// BOOL->INT32->int + [FieldOffset(0)] + [MarshalAs(UnmanagedType.I1)] + public bool xbool; + + /// int + [FieldOffset(0)] + public int err; + + /// int + [FieldOffset(0)] + public int w; + + [FieldOffset(0)] + public sref sref; + + [FieldOffset(0)] + public mref mref; + + [FieldOffset(0)] + public array array; + + [FieldOffset(0)] + public flow flow; + + [FieldOffset(0)] + public bigdata bigdata; +} + +[StructLayout(LayoutKind.Sequential)] +public struct xloper12 +{ + public val val; + + /// DWORD->int + public int xltype; +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Util.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Util.cs new file mode 100644 index 00000000..5dbac5b3 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Util.cs @@ -0,0 +1,23 @@ +namespace ExcelDna.COMWrappers.NativeAOT +{ + public static class Util + { + public static object? GetExcelApplication() + { + foreach (var w in OpenWindowGetter.GetOpenWindows()) + { + if (w.Value.EndsWith("Excel")) + return GetExcelObject(w.Key); + //Console.WriteLine(w.Value); + + } + + return null; + } + + static object? GetExcelObject(System.IntPtr w) + { + return Excel.GetApplicationFromWindow(w); + } + } +} diff --git a/Source/ExcelDna.Integration/ComInterop.cs b/Source/ExcelDna.Integration/ComInterop.cs index 6d7ba34f..53441810 100644 --- a/Source/ExcelDna.Integration/ComInterop.cs +++ b/Source/ExcelDna.Integration/ComInterop.cs @@ -7,13 +7,14 @@ using ExcelDna.ComInterop; using HRESULT = System.Int32; -using IID = System.Guid; -using CLSID = System.Guid; -using DWORD = System.Int32; +using IID = System.Guid; +using CLSID = System.Guid; +using DWORD = System.Int32; using System.Runtime.CompilerServices; using System.Reflection; using System.Collections; using System.Threading; +using ExcelDna.Integration; namespace ExcelDna.ComInterop { @@ -173,11 +174,11 @@ internal interface ICustomTaskPaneConsumer public interface IRibbonControl { [DispId(1)] - string Id { [return: MarshalAs(UnmanagedType.BStr)] [DispId(1)] get; } + string Id { [return: MarshalAs(UnmanagedType.BStr)][DispId(1)] get; } [DispId(2)] - object Context { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(2)] get; } + object Context { [return: MarshalAs(UnmanagedType.IDispatch)][DispId(2)] get; } [DispId(3)] - string Tag { [return: MarshalAs(UnmanagedType.BStr)] [DispId(3)] get; } + string Tag { [return: MarshalAs(UnmanagedType.BStr)][DispId(3)] get; } } [ComImport] @@ -191,14 +192,14 @@ public interface IRibbonUI [DispId(2)] void InvalidateControl([In, MarshalAs(UnmanagedType.BStr)] string ControlID); [DispId(3)] - void InvalidateControlMso([MarshalAs(UnmanagedType.BStr)] [In] string ControlID); + void InvalidateControlMso([MarshalAs(UnmanagedType.BStr)][In] string ControlID); // The ActiveTab methods were added in Office 2010 [DispId(4)] - void ActivateTab([MarshalAs(UnmanagedType.BStr)] [In] string ControlID); + void ActivateTab([MarshalAs(UnmanagedType.BStr)][In] string ControlID); [DispId(5)] - void ActivateTabMso([MarshalAs(UnmanagedType.BStr)] [In] string ControlID); + void ActivateTabMso([MarshalAs(UnmanagedType.BStr)][In] string ControlID); [DispId(6)] - void ActivateTabQ([MarshalAs(UnmanagedType.BStr)] [In] string ControlID, [MarshalAs(UnmanagedType.BStr)] [In] string Namespace); + void ActivateTabQ([MarshalAs(UnmanagedType.BStr)][In] string ControlID, [MarshalAs(UnmanagedType.BStr)][In] string Namespace); } //// Actually from System.Windows.Forms.UnsafeNativeMethods @@ -248,23 +249,23 @@ public enum MsoCTPDockPositionRestrict public interface ICustomTaskPane { [DispId(0)] - string Title { [return: MarshalAs(UnmanagedType.BStr)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0)] get; } + string Title { [return: MarshalAs(UnmanagedType.BStr)][MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0)] get; } [DispId(1)] - object Application { [return: MarshalAs(UnmanagedType.IDispatch)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(1)] get; } + object Application { [return: MarshalAs(UnmanagedType.IDispatch)][MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(1)] get; } [DispId(2)] - object Window { [return: MarshalAs(UnmanagedType.IDispatch)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(2)] get; } + object Window { [return: MarshalAs(UnmanagedType.IDispatch)][MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(2)] get; } [DispId(3)] - bool Visible { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(3)] get; [param: In] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(3)] set; } + bool Visible { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(3)] get; [param: In][MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(3)] set; } [DispId(4)] - object ContentControl { [return: MarshalAs(UnmanagedType.IDispatch)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(4)] get; } + object ContentControl { [return: MarshalAs(UnmanagedType.IDispatch)][MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(4)] get; } [DispId(5)] - int Height { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(5)] get; [param: In] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(5)] set; } + int Height { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(5)] get; [param: In][MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(5)] set; } [DispId(6)] - int Width { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(6)] get; [param: In] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(6)] set; } + int Width { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(6)] get; [param: In][MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(6)] set; } [DispId(7)] - MsoCTPDockPosition DockPosition { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(7)] get; [param: In] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(7)] set; } + MsoCTPDockPosition DockPosition { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(7)] get; [param: In][MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(7)] set; } [DispId(8)] - MsoCTPDockPositionRestrict DockPositionRestrict { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(8)] get; [param: In] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(8)] set; } + MsoCTPDockPositionRestrict DockPositionRestrict { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(8)] get; [param: In][MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(8)] set; } [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(9)] void Delete(); } @@ -596,7 +597,7 @@ public interface IRtdServer [DispId(12)] [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] Array RefreshData(ref int topicCount); - + // // Summary: // Notifies a real-time data (RTD) server application that a topic is no longer @@ -847,3 +848,43 @@ out UInt32 pArgErr } #endregion + +namespace ExcelDna.ComInterop +{ + public interface IType + { + object GetProperty(string name, object comObject); + object GetIndex(int i, object comObject); + object Invoke(string name, object[] args, object comObject); + bool Is(ref Guid guid, object comObject); + } + + internal static class Util + { + public static IType TypeAdapter + { get; } = NativeAOT.IsActive ? NativeAOT.TypeAdapter : new TypeAdapter(); + } + + internal class TypeAdapter : IType + { + public object GetProperty(string name, object comObject) + { + return comObject.GetType().InvokeMember(name, BindingFlags.GetProperty, null, comObject, null); + } + + public object GetIndex(int i, object comObject) + { + return comObject.GetType().InvokeMember("", BindingFlags.GetProperty, null, comObject, new object[] { i }); + } + + public bool Is(ref CLSID guid, object comObject) + { + throw new NotImplementedException(); + } + + public object Invoke(string name, object[] args, object comObject) + { + throw new NotImplementedException(); + } + } +} diff --git a/Source/ExcelDna.Integration/ExcelCommandBars.cs b/Source/ExcelDna.Integration/ExcelCommandBars.cs index 80091ed4..0cfc67bb 100644 --- a/Source/ExcelDna.Integration/ExcelCommandBars.cs +++ b/Source/ExcelDna.Integration/ExcelCommandBars.cs @@ -45,16 +45,31 @@ public static class ExcelCommandBarUtil // List of loaded CustomUI static List loadedCustomUIs = new List(); + //static Util util = new Util(); + + //private class Util : ICommandBarUtil + //{ + // public ICommandBars GetCommandBars() + // { + // return ExcelCommandBarUtil.GetCommandBars(); + // } + //} + + //public static ICommandBarUtil GetUtil() + //{ + // return util; + //} + // Helper to call Application.CommandBars public static CommandBars GetCommandBars() { - Application excelApp = new Application(ExcelDnaUtil.Application); + Application excelApp = new Application(NativeAOT.IsActive ? NativeAOT.ExcelApplication : ExcelDnaUtil.Application); return excelApp.CommandBars; } public static void LoadCommandBars(string xmlCustomUI) { - LoadCommandBars(xmlCustomUI, delegate(string imageName) { return null; }); + LoadCommandBars(xmlCustomUI, delegate (string imageName) { return null; }); } public static void LoadCommandBars(string xmlCustomUI, GetImageDelegate getImage) @@ -454,20 +469,20 @@ private static void ApplyControlAttribute(CommandBarControl control, string attr private class Application { object _object; - Type _type; + //Type _type; public Application(object application) { _object = application; - _type = _object.GetType(); + // _type = _object.GetType(); } public CommandBars CommandBars { get { - object commandBars = _type.InvokeMember("CommandBars", BindingFlags.GetProperty, null, _object, null); - return new CommandBars(commandBars); + // object commandBars = _type.InvokeMember("CommandBars", BindingFlags.GetProperty, null, _object, null); + return new CommandBars(ComInterop.Util.TypeAdapter.GetProperty("CommandBars", _object)); } } } @@ -506,7 +521,8 @@ public CommandBarControls Controls { get { - object controls = ComObjectType.InvokeMember("Controls", BindingFlags.GetProperty, null, ComObject, null); + object controls = ComInterop.Util.TypeAdapter.GetProperty("Controls", ComObject); + //object controls = ComObjectType.InvokeMember("Controls", BindingFlags.GetProperty, null, ComObject, null); return new CommandBarControls(controls); } } @@ -583,7 +599,8 @@ public CommandBar this[int i] { get { - object commandBar = _type.InvokeMember("", BindingFlags.GetProperty, null, _object, new object[] { i }); + object commandBar = ComInterop.Util.TypeAdapter.GetIndex(i, _object); + //object commandBar = _type.InvokeMember("", BindingFlags.GetProperty, null, _object, new object[] { i }); return new CommandBar(commandBar); } } @@ -643,29 +660,49 @@ internal static CommandBarControl CreateCommandBarControl(MsoControlType control // In this case we check the interfaces for the right type internal static CommandBarControl CreateCommandBarControl(object commandBarControl) { - IntPtr pUnk = Marshal.GetIUnknownForObject(commandBarControl); - - IntPtr pButton; - Marshal.QueryInterface(pUnk, ref guidCommandBarButton, out pButton); - if (pButton != IntPtr.Zero) + if (ComInterop.Util.TypeAdapter.Is(ref guidCommandBarButton, commandBarControl)) { + System.Diagnostics.Trace.WriteLine("[CreateCommandBarControl] is CommandBarButton"); return new CommandBarButton(commandBarControl); } - IntPtr pPopup; - Marshal.QueryInterface(pUnk, ref guidCommandBarPopup, out pPopup); - if (pPopup != IntPtr.Zero) + if (ComInterop.Util.TypeAdapter.Is(ref guidCommandBarPopup, commandBarControl)) { + System.Diagnostics.Trace.WriteLine("[CreateCommandBarControl] is CommandBarPopup"); return new CommandBarPopup(commandBarControl); } - IntPtr pComboBox; - Marshal.QueryInterface(pUnk, ref guidCommandBarPopup, out pComboBox); - if (pComboBox != IntPtr.Zero) + if (ComInterop.Util.TypeAdapter.Is(ref guidCommandBarComboBox, commandBarControl)) { + System.Diagnostics.Trace.WriteLine("[CreateCommandBarControl] is CommandBarComboBox"); return new CommandBarComboBox(commandBarControl); } + //IntPtr pUnk = Marshal.GetIUnknownForObject(commandBarControl); + + //IntPtr pButton; + //Marshal.QueryInterface(pUnk, ref guidCommandBarButton, out pButton); + //if (pButton != IntPtr.Zero) + //{ + // return new CommandBarButton(commandBarControl); + //} + + //IntPtr pPopup; + //Marshal.QueryInterface(pUnk, ref guidCommandBarPopup, out pPopup); + //if (pPopup != IntPtr.Zero) + //{ + // return new CommandBarPopup(commandBarControl); + //} + + //IntPtr pComboBox; + //Marshal.QueryInterface(pUnk, ref guidCommandBarPopup, out pComboBox); + //if (pComboBox != IntPtr.Zero) + //{ + // return new CommandBarComboBox(commandBarControl); + //} + + System.Diagnostics.Trace.WriteLine("[CreateCommandBarControl] is ???"); + return new CommandBarControl(commandBarControl); } @@ -679,7 +716,8 @@ public string Caption { get { - return (string)ComObjectType.InvokeMember("Caption", BindingFlags.GetProperty, null, ComObject, null); + return (string)ComInterop.Util.TypeAdapter.GetProperty("Caption", ComObject); + //return (string)ComObjectType.InvokeMember("Caption", BindingFlags.GetProperty, null, ComObject, null); } set { @@ -838,15 +876,18 @@ public CommandBarControl this[int id] { get { - object commandBarControl = ComObjectTtpe.InvokeMember( - "", BindingFlags.GetProperty, null, ComObject, new object[] { id }); + object commandBarControl = ComInterop.Util.TypeAdapter.GetIndex(id, ComObject); + + //object commandBarControl = ComObjectTtpe.InvokeMember( + //"", BindingFlags.GetProperty, null, ComObject, new object[] { id }); return CommandBarControl.CreateCommandBarControl(commandBarControl); } } public int Count() { - object i = ComObjectTtpe.InvokeMember("Count", BindingFlags.GetProperty, null, ComObject, null); + object i = ComInterop.Util.TypeAdapter.GetProperty("Count", ComObject); + //object i = ComObjectTtpe.InvokeMember("Count", BindingFlags.GetProperty, null, ComObject, null); return Convert.ToInt32(i); } @@ -871,8 +912,9 @@ internal CommandBarControl FindOrAdd(MsoControlType controlType, string name, ob } } - object /*CommandBarControl*/ newControl = ComObjectTtpe.InvokeMember("Add", BindingFlags.InvokeMethod, null, ComObject, - new object[] { controlType, Id, Parameter, Before, Temporary }); + object /*CommandBarControl*/ newControl = ComInterop.Util.TypeAdapter.Invoke("Add", new object[] { controlType, Id, Parameter, Before, Temporary }, ComObject); + //object /*CommandBarControl*/ newControl = ComObjectTtpe.InvokeMember("Add", BindingFlags.InvokeMethod, null, ComObject, + // new object[] { controlType, Id, Parameter, Before, Temporary }); return CommandBarControl.CreateCommandBarControl(controlType, newControl); } diff --git a/Source/ExcelDna.Integration/ICommandBars.cs b/Source/ExcelDna.Integration/ICommandBars.cs new file mode 100644 index 00000000..3e5d7ae9 --- /dev/null +++ b/Source/ExcelDna.Integration/ICommandBars.cs @@ -0,0 +1,17 @@ +namespace ExcelDna.Integration.CustomUI +{ + public interface ICommandBar + { + + } + + public interface ICommandBars + { + ICommandBar this[string name] { get; } + } + + public interface ICommandBarUtil + { + ICommandBars GetCommandBars(); + } +} diff --git a/Source/ExcelDna.Integration/MenuManager.cs b/Source/ExcelDna.Integration/MenuManager.cs index 831e61b9..55ff1a0a 100644 --- a/Source/ExcelDna.Integration/MenuManager.cs +++ b/Source/ExcelDna.Integration/MenuManager.cs @@ -14,7 +14,7 @@ namespace ExcelDna.Integration /// TODO: Can we integrate with ExcelCommandBars? /// Hierarchical menus. /// - + // CAUTION: This 'internal' class is called via reflection by the ExcelDna Loader. [UsedImplicitly(ImplicitUseTargetFlags.WithMembers)] internal static class MenuManager @@ -86,9 +86,9 @@ public void AddCommandMenu(string commandName, string menuName, string menuText, // Throws Access violation exception Excel if I add a string to description or helptopic XlCall.Excel(XlCall.xlfAddMenu, 1.0 /*Worksheet and Macro sheet*/, new object[,] { { menuName, null, null, null, null}, - { menuText, commandName, - null/*shortcut_key (Mac Only)*/, - null, // mi.Description, + { menuText, commandName, + null/*shortcut_key (Mac Only)*/, + null, // mi.Description, null /*mi.HelpTopic*/} }); _addedMenus.Add(menuName); done = true; @@ -105,11 +105,11 @@ public void AddCommandMenu(string commandName, string menuName, string menuText, XlCall.Excel(XlCall.xlfAddCommand, 1.0 /*Worksheet and Macro sheet*/, menuName, - new object[] { - menuText, - commandName, - null/*shortcut_key (Mac Only)*/, - null, // mi.Description, + new object[] { + menuText, + commandName, + null/*shortcut_key (Mac Only)*/, + null, // mi.Description, null /*mi.HelpTopic*/}); _addedMenuEntries.Add(new MenuEntry(commandName, menuName, menuText)); } @@ -171,7 +171,6 @@ public void AddCommandMenu(string commandName, string menuName, string menuText, if (!_foundMenus.TryGetValue(menuName, out menu)) { // We've not seen this menu before - // Check if the menu exists CommandBars commandBars = ExcelCommandBarUtil.GetCommandBars(); CommandBar worksheetBar = commandBars[1]; @@ -219,6 +218,7 @@ public void AddCommandMenu(string commandName, string menuName, string menuText, } catch (Exception e) { + System.Diagnostics.Trace.WriteLine("[MenuManager.AddCommandMenu] " + e.ToString()); Logger.Initialization.Error(e, "MenuManager.AddCommandMenu Error"); } } diff --git a/Source/ExcelDna.Integration/NativeAOT.cs b/Source/ExcelDna.Integration/NativeAOT.cs index a7cd2cd1..ee11ed3c 100644 --- a/Source/ExcelDna.Integration/NativeAOT.cs +++ b/Source/ExcelDna.Integration/NativeAOT.cs @@ -6,6 +6,8 @@ namespace ExcelDna.Integration public class NativeAOT { public static bool IsActive { get; set; } + public static object ExcelApplication { get; set; } + public static ComInterop.IType TypeAdapter { get; set; } public static List MethodsForRegistration { get; } = new List(); public static List ExcelAddIns { get; } = new List(); diff --git a/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs b/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs index 7d649088..50bd786a 100644 --- a/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs +++ b/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs @@ -29,6 +29,8 @@ public unsafe class AddInInitialize public static short Initialize(void* xlAddInExportInfoAddress, void* hModuleXll, void* pPathXLL, byte disableAssemblyContextUnload, void* pTempDirPath) { ExcelDna.Integration.NativeAOT.IsActive = true; + ExcelDna.Integration.NativeAOT.ExcelApplication = ExcelDna.COMWrappers.NativeAOT.Util.GetExcelApplication()!; + ExcelDna.Integration.NativeAOT.TypeAdapter = new ExcelDna.COMWrappers.NativeAOT.TypeAdapter(); [ADDINS] diff --git a/Source/ExcelDna.sln b/Source/ExcelDna.sln index 2231987f..7b7b05aa 100644 --- a/Source/ExcelDna.sln +++ b/Source/ExcelDna.sln @@ -146,6 +146,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExcelDna.AddIn.RuntimeTests {D50C3A8E-46F1-F61B-C8F5-ECDA05995EEB} = {D50C3A8E-46F1-F61B-C8F5-ECDA05995EEB} EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExcelDna.COMWrappers.NativeAOT", "ExcelDna.COMWrappers.NativeAOT\ExcelDna.COMWrappers.NativeAOT.csproj", "{6D863736-3512-4595-8432-4E33D123DCAC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -306,6 +308,14 @@ Global {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Release|Win32.ActiveCfg = Release|Any CPU {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Release|x64.ActiveCfg = Release|Any CPU {1EC2EE86-7C59-4CA9-9D6A-FBF206DA9D3F}.Release|x64.Build.0 = Release|Any CPU + {6D863736-3512-4595-8432-4E33D123DCAC}.Debug|Win32.ActiveCfg = Debug|Any CPU + {6D863736-3512-4595-8432-4E33D123DCAC}.Debug|Win32.Build.0 = Debug|Any CPU + {6D863736-3512-4595-8432-4E33D123DCAC}.Debug|x64.ActiveCfg = Debug|Any CPU + {6D863736-3512-4595-8432-4E33D123DCAC}.Debug|x64.Build.0 = Debug|Any CPU + {6D863736-3512-4595-8432-4E33D123DCAC}.Release|Win32.ActiveCfg = Release|Any CPU + {6D863736-3512-4595-8432-4E33D123DCAC}.Release|Win32.Build.0 = Release|Any CPU + {6D863736-3512-4595-8432-4E33D123DCAC}.Release|x64.ActiveCfg = Release|Any CPU + {6D863736-3512-4595-8432-4E33D123DCAC}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/Commands.cs b/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/Commands.cs index 4352ef67..c433386b 100644 --- a/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/Commands.cs +++ b/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/Commands.cs @@ -4,7 +4,7 @@ namespace ExcelDna.AddIn.RuntimeTestsAOT { public class Commands { - [ExcelCommand(MenuText = "")] + [ExcelCommand(MenuText = "MyNativeCommand")] public static void NativeCommand() { System.Diagnostics.Trace.WriteLine("RuntimeTestsAOT NativeCommand"); diff --git a/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/ExcelDna.AddIn.RuntimeTestsAOT.csproj b/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/ExcelDna.AddIn.RuntimeTestsAOT.csproj index d64024d1..a625391c 100644 --- a/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/ExcelDna.AddIn.RuntimeTestsAOT.csproj +++ b/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/ExcelDna.AddIn.RuntimeTestsAOT.csproj @@ -25,12 +25,13 @@ + - + From ac26aeda80cdce858a7fc536f851eb740138f32d Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Tue, 11 Mar 2025 21:11:33 +0500 Subject: [PATCH 22/60] Added support for optional missing parameters. --- .../ComApi/ExcelObject.cs | 2 -- .../Types/Marshalling/Variant.cs | 21 ++++++++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ExcelObject.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ExcelObject.cs index ff6b4d01..cda95132 100644 --- a/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ExcelObject.cs +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ExcelObject.cs @@ -119,8 +119,6 @@ object[] args for (int i = 0; i < args.Length; ++i) { object? o = args[i].GetType().IsEnum ? (int)args[i] : args[i]; - if (o == Type.Missing) - o = null; System.Diagnostics.Trace.WriteLine("[InvokeMember] " + name + " " + o?.GetType().ToString()); a[i] = new Variant(o); diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Variant.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Variant.cs index 68f59da3..b408dd1a 100644 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Variant.cs +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Variant.cs @@ -8,8 +8,19 @@ namespace Addin.Types.Marshalling; [CustomMarshaller(typeof(Managed.Variant), MarshalMode.Default, typeof(Variant))] public static class Variant { + public const int DISP_E_PARAMNOTFOUND = -2147352572; + public static Unmanaged.Variant ConvertToUnmanaged(Managed.Variant managed) { + if (managed.Value == Type.Missing) + { + return new Unmanaged.Variant + { + vt = (ushort)VariantType.VT_ERROR, + scode = DISP_E_PARAMNOTFOUND, + }; + } + return managed.Value switch { bool boolVal @@ -27,15 +38,18 @@ string bstrVal vt = (ushort)VariantType.VT_BSTR, bstrVal = Marshal.StringToBSTR(bstrVal), }, - null => new Unmanaged.Variant { }, + null => new Unmanaged.Variant { vt = (ushort)VariantType.VT_NULL, }, _ => throw new NotImplementedException(managed.Value.GetType().ToString()) - , + , }; } public static unsafe Managed.Variant ConvertToManaged(Unmanaged.Variant unmanaged) { + if ((VariantType)unmanaged.vt == VariantType.VT_ERROR && unmanaged.scode == DISP_E_PARAMNOTFOUND) + return new Managed.Variant(Type.Missing); + return (VariantType)unmanaged.vt switch { VariantType.VT_BOOL @@ -54,7 +68,8 @@ public static unsafe Managed.Variant ConvertToManaged(Unmanaged.Variant unmanage ), }, VariantType.VT_EMPTY => new Managed.Variant { }, - _ => throw new NotImplementedException(), + VariantType.VT_NULL => new Managed.Variant { }, + _ => throw new NotImplementedException(unmanaged.vt.ToString()), }; } } From d72fdbd5b9ca1d885a0a1a38ceab6b9d6a454f85 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Tue, 11 Mar 2025 21:12:41 +0500 Subject: [PATCH 23/60] Fixed DispParams parameters order. --- .../Types/Marshalling/DispParams.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/DispParams.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/DispParams.cs index f799f926..390b3a1d 100644 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/DispParams.cs +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/DispParams.cs @@ -14,7 +14,7 @@ public static unsafe Unmanaged.DispParams ConvertToUnmanaged(Managed.DispParams rgdispidNamedArgs = &managed.rgdispidNamedArgs, rgvarg = managed.rgvarg != null - ? Array.ArrayToPtr(managed.rgvarg.Select(Variant.ConvertToUnmanaged).ToArray()) + ? Array.ArrayToPtr(managed.rgvarg.Reverse().Select(Variant.ConvertToUnmanaged).ToArray()) : nint.Zero }; } @@ -29,6 +29,7 @@ public static unsafe Managed.DispParams ConvertToManaged(Unmanaged.DispParams un rgvarg = Array .PtrToArray(unmanaged.rgvarg, unmanaged.cArgs) .Select(Variant.ConvertToManaged) + .Reverse() .ToArray(), }; } From 1aefdc83b5bcaaa7e80e09a26a2f1e6f0b662259 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Tue, 11 Mar 2025 21:13:48 +0500 Subject: [PATCH 24/60] Added Is and Invoke implementation to TypeAdapter. --- Source/ExcelDna.Integration/ComInterop.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Source/ExcelDna.Integration/ComInterop.cs b/Source/ExcelDna.Integration/ComInterop.cs index 53441810..9a674ddb 100644 --- a/Source/ExcelDna.Integration/ComInterop.cs +++ b/Source/ExcelDna.Integration/ComInterop.cs @@ -879,12 +879,16 @@ public object GetIndex(int i, object comObject) public bool Is(ref CLSID guid, object comObject) { - throw new NotImplementedException(); + IntPtr pUnk = Marshal.GetIUnknownForObject(comObject); + + IntPtr pButton; + Marshal.QueryInterface(pUnk, ref guid, out pButton); + return (pButton != IntPtr.Zero); } public object Invoke(string name, object[] args, object comObject) { - throw new NotImplementedException(); + return comObject.GetType().InvokeMember(name, BindingFlags.InvokeMethod, null, comObject, args); } } } From 5ee45403e5984e9370c36002ea916c596ab6e97f Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Tue, 11 Mar 2025 21:16:06 +0500 Subject: [PATCH 25/60] Added a test command. --- Source/ExcelDna.Test/Commmands.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Source/ExcelDna.Test/Commmands.cs diff --git a/Source/ExcelDna.Test/Commmands.cs b/Source/ExcelDna.Test/Commmands.cs new file mode 100644 index 00000000..d5958a18 --- /dev/null +++ b/Source/ExcelDna.Test/Commmands.cs @@ -0,0 +1,18 @@ +using ExcelDna.Integration; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ExcelDna.Test +{ + public class Commands + { + [ExcelCommand(MenuText = "MyTestCommand")] + public static void MyTestCommand() + { + System.Diagnostics.Trace.WriteLine("ExcelDna.Test MyTestCommand"); + } + } +} From 8839e3d045affab1ed272370b9a0fa7ae30ddd7f Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Wed, 12 Mar 2025 07:38:43 +0500 Subject: [PATCH 26/60] Implemented SetProperty. --- .../ComApi/ExcelObject.cs | 13 +++++++++++++ .../ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs | 6 ++++++ Source/ExcelDna.Integration/ComInterop.cs | 6 ++++++ 3 files changed, 25 insertions(+) diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ExcelObject.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ExcelObject.cs index cda95132..b6b27f8a 100644 --- a/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ExcelObject.cs +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ExcelObject.cs @@ -61,6 +61,19 @@ public override bool TrySetMember(SetMemberBinder binder, object value) return true; } + public void SetProperty(string name, object value) + { + var dispParams = new DispParams + { + rgvarg = [new Variant(value)], + rgdispidNamedArgs = DISPID_PROPERTYPUT, + cArgs = 1, + cNamedArgs = 1 + }; + + InvokeWrapper(name, INVOKEKIND.INVOKE_PROPERTYPUT, dispParams); + } + public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object? result) { var index = (int)indexes[0]; diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs b/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs index 9a2f11b4..39991e70 100644 --- a/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs +++ b/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs @@ -48,5 +48,11 @@ public object Invoke(string name, object[] args, object comObject) return result!; } + + public void SetProperty(string name, object value, object comObject) + { + var excelWindowWrapper = new ExcelObject(comObject as IDispatch); + excelWindowWrapper.SetProperty(name, value); + } } } diff --git a/Source/ExcelDna.Integration/ComInterop.cs b/Source/ExcelDna.Integration/ComInterop.cs index 9a674ddb..ae60207a 100644 --- a/Source/ExcelDna.Integration/ComInterop.cs +++ b/Source/ExcelDna.Integration/ComInterop.cs @@ -854,6 +854,7 @@ namespace ExcelDna.ComInterop public interface IType { object GetProperty(string name, object comObject); + void SetProperty(string name, object value, object comObject); object GetIndex(int i, object comObject); object Invoke(string name, object[] args, object comObject); bool Is(ref Guid guid, object comObject); @@ -890,5 +891,10 @@ public object Invoke(string name, object[] args, object comObject) { return comObject.GetType().InvokeMember(name, BindingFlags.InvokeMethod, null, comObject, args); } + + public void SetProperty(string name, object value, object comObject) + { + comObject.GetType().InvokeMember(name, BindingFlags.SetProperty, null, comObject, new object[] { value }); + } } } From ec6b9968dea75ad603ec047a776679a1ccc0c829 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Wed, 12 Mar 2025 07:49:33 +0500 Subject: [PATCH 27/60] Completed adding a command to Add-ins ribbon. --- Source/ExcelDna.Integration/ExcelCommandBars.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Source/ExcelDna.Integration/ExcelCommandBars.cs b/Source/ExcelDna.Integration/ExcelCommandBars.cs index 0cfc67bb..1532146c 100644 --- a/Source/ExcelDna.Integration/ExcelCommandBars.cs +++ b/Source/ExcelDna.Integration/ExcelCommandBars.cs @@ -721,7 +721,8 @@ public string Caption } set { - ComObjectType.InvokeMember("Caption", BindingFlags.SetProperty, null, ComObject, new object[] { value }); + ComInterop.Util.TypeAdapter.SetProperty("Caption", value, ComObject); + //ComObjectType.InvokeMember("Caption", BindingFlags.SetProperty, null, ComObject, new object[] { value }); } } @@ -757,7 +758,9 @@ public string OnAction } set { - ComObjectType.InvokeMember("OnAction", BindingFlags.SetProperty, null, ComObject, new object[] { value }); + ComInterop.Util.TypeAdapter.SetProperty("OnAction", value, ComObject); + + //ComObjectType.InvokeMember("OnAction", BindingFlags.SetProperty, null, ComObject, new object[] { value }); } } @@ -1096,7 +1099,9 @@ public CommandBarControls Controls { get { - object controls = ComObjectType.InvokeMember("Controls", BindingFlags.GetProperty, null, ComObject, null); + object controls = ComInterop.Util.TypeAdapter.GetProperty("Controls", ComObject); + + //object controls = ComObjectType.InvokeMember("Controls", BindingFlags.GetProperty, null, ComObject, null); return new CommandBarControls(controls); } } From 2797c5bebcb3fdebaaae885249ca882151738739 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sat, 15 Mar 2025 12:13:14 +0500 Subject: [PATCH 28/60] Implemented ExcelDnaUtil.ApplicationObject. --- .../ComApi/ExcelObject.cs | 14 ++++++ .../TypeAdapter.cs | 18 ++++++++ Source/ExcelDna.Integration/ComInterop.cs | 19 ++++++++ Source/ExcelDna.Integration/Excel.cs | 44 ++++++++++++------- .../ExcelDna.Integration/ExcelCommandBars.cs | 3 +- 5 files changed, 81 insertions(+), 17 deletions(-) diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ExcelObject.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ExcelObject.cs index b6b27f8a..1ea9c3e0 100644 --- a/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ExcelObject.cs +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ExcelObject.cs @@ -37,6 +37,20 @@ public ExcelObject(IDispatch? interfacePtr = null) return InvokeWrapper(name, INVOKEKIND.INVOKE_PROPERTYGET, dispParams); } + public bool HasProperty(string name) + { + try + { + GetDispIDs(name); + return true; + } + catch + { + } + + return false; + } + public override bool TryGetMember(GetMemberBinder binder, out object? result) { DispParams dispParams = new(); diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs b/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs index 39991e70..b22adbf7 100644 --- a/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs +++ b/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs @@ -1,5 +1,7 @@ using Addin.ComApi; using ExcelDna.ComInterop; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; namespace ExcelDna.COMWrappers.NativeAOT { @@ -54,5 +56,21 @@ public void SetProperty(string name, object value, object comObject) var excelWindowWrapper = new ExcelObject(comObject as IDispatch); excelWindowWrapper.SetProperty(name, value); } + + public object GetObject(IntPtr pUnk) + { + ComWrappers cw = new StrategyBasedComWrappers(); + return cw.GetOrCreateObjectForComInstance(pUnk, CreateObjectFlags.None); + } + + public void ReleaseObject(object comObject) + { + } + + public bool HasProperty(string name, object comObject) + { + var excelWindowWrapper = new ExcelObject(comObject as IDispatch); + return excelWindowWrapper.HasProperty(name); + } } } diff --git a/Source/ExcelDna.Integration/ComInterop.cs b/Source/ExcelDna.Integration/ComInterop.cs index ae60207a..8deef734 100644 --- a/Source/ExcelDna.Integration/ComInterop.cs +++ b/Source/ExcelDna.Integration/ComInterop.cs @@ -853,6 +853,10 @@ namespace ExcelDna.ComInterop { public interface IType { + object GetObject(IntPtr pUnk); + void ReleaseObject(object comObject); + + bool HasProperty(string name, object comObject); object GetProperty(string name, object comObject); void SetProperty(string name, object value, object comObject); object GetIndex(int i, object comObject); @@ -896,5 +900,20 @@ public void SetProperty(string name, object value, object comObject) { comObject.GetType().InvokeMember(name, BindingFlags.SetProperty, null, comObject, new object[] { value }); } + + public object GetObject(IntPtr pUnk) + { + return Marshal.GetObjectForIUnknown(pUnk); + } + + public void ReleaseObject(object comObject) + { + Marshal.ReleaseComObject(comObject); + } + + public bool HasProperty(string name, object comObject) + { + return ComInterop.DispatchHelper.HasProperty(comObject, name); + } } } diff --git a/Source/ExcelDna.Integration/Excel.cs b/Source/ExcelDna.Integration/Excel.cs index 140539da..77b32279 100644 --- a/Source/ExcelDna.Integration/Excel.cs +++ b/Source/ExcelDna.Integration/Excel.cs @@ -215,9 +215,17 @@ static bool IsWindowOfThisExcel(IntPtr hWnd) #region Get Application COM Object // CONSIDER: ThreadStatic not needed anymore - only cached and used on main thread anyway. // [ThreadStatic] - static Microsoft.Office.Interop.Excel.Application _application; + static object _application; static readonly CultureInfo _enUsCulture = new CultureInfo(1033); public static Microsoft.Office.Interop.Excel.Application Application + { + get + { + return (Microsoft.Office.Interop.Excel.Application)ApplicationObject; + } + } + + internal static object ApplicationObject { get { @@ -282,11 +290,11 @@ private static bool IsExcelApiAvailable() return true; } - private static Microsoft.Office.Interop.Excel.Application GetApplication(bool allowProtected, out bool isProtected) + private static object GetApplication(bool allowProtected, out bool isProtected) { // Don't cache the one we get from the Window, it keeps Excel alive! // (?? Really ?? - Probably only when we're not on the main thread...) - Microsoft.Office.Interop.Excel.Application application = GetApplicationFromWindows(allowProtected, out isProtected); + object application = GetApplicationFromWindows(allowProtected, out isProtected); if (application != null) return application; // DOCUMENT: Under some circumstances, the C API and Automation interfaces are not available. @@ -302,11 +310,11 @@ private static Microsoft.Office.Interop.Excel.Application GetApplication(bool al return GetApplicationFromNewWorkbook(allowProtected, out isProtected); } - private static Microsoft.Office.Interop.Excel.Application GetApplicationFromNewWorkbook(bool allowProtected, out bool isProtected) + private static object GetApplicationFromNewWorkbook(bool allowProtected, out bool isProtected) { // Create new workbook with the right stuff // Echo calls removed for Excel 2013 - this caused trouble in the Excel 2013 'browse' scenario. - Microsoft.Office.Interop.Excel.Application application; + object application; bool isExcelPre15 = SafeIsExcelVersionPre15; if (isExcelPre15) XlCall.Excel(XlCall.xlcEcho, false); try @@ -377,7 +385,7 @@ internal static object GetApplicationNotProtectedNoThrow() return application; } - static Microsoft.Office.Interop.Excel.Application GetApplicationFromWindows(bool allowProtected, out bool isProtected) + static object GetApplicationFromWindows(bool allowProtected, out bool isProtected) { if (SafeIsExcelVersionPre15) { @@ -389,9 +397,9 @@ static Microsoft.Office.Interop.Excel.Application GetApplicationFromWindows(bool // Enumerate through all top-level windows of the main thread, // and for those of class XLMAIN, dig down by calling GetApplicationFromWindow. - static Microsoft.Office.Interop.Excel.Application GetApplicationFromWindows15(bool allowProtected, out bool isProtected) + static object GetApplicationFromWindows15(bool allowProtected, out bool isProtected) { - Microsoft.Office.Interop.Excel.Application application = null; + object application = null; StringBuilder buffer = new StringBuilder(256); bool localIsProtected = false; @@ -413,11 +421,11 @@ static Microsoft.Office.Interop.Excel.Application GetApplicationFromWindows15(bo return application; // May or may not be null } - private static Microsoft.Office.Interop.Excel.Application GetApplicationFromWindow(IntPtr hWndMain, bool allowProtected, out bool isProtected) + private static object GetApplicationFromWindow(IntPtr hWndMain, bool allowProtected, out bool isProtected) { // This is Andrew Whitechapel's plan for getting the Application object. // It does not work when there are no Workbooks open. - Microsoft.Office.Interop.Excel.Application app = null; + object app = null; StringBuilder cname = new StringBuilder(256); bool localIsProtected = false; @@ -438,14 +446,15 @@ private static Microsoft.Office.Interop.Excel.Application GetApplicationFromWind } // Marshal to .NET, then call .Application - object obj = Marshal.GetObjectForIUnknown(pUnk); + object obj = ComInterop.Util.TypeAdapter.GetObject(pUnk); Marshal.Release(pUnk); try { - if (ComInterop.DispatchHelper.HasProperty(obj, "Application")) + if (ComInterop.Util.TypeAdapter.HasProperty("Application", obj)) { - app = (Microsoft.Office.Interop.Excel.Application)obj.GetType().InvokeMember("Application", BindingFlags.GetProperty, null, obj, null, _enUsCulture); + app = ComInterop.Util.TypeAdapter.GetProperty("Application", obj); + //app = obj.GetType().InvokeMember("Application", BindingFlags.GetProperty, null, obj, null, _enUsCulture); } else { @@ -455,8 +464,10 @@ private static Microsoft.Office.Interop.Excel.Application GetApplicationFromWind { try { - object workbook = obj.GetType().InvokeMember("Workbook", BindingFlags.GetProperty, null, obj, null, _enUsCulture); - app = (Microsoft.Office.Interop.Excel.Application)workbook.GetType().InvokeMember("Application", BindingFlags.GetProperty, null, workbook, null, _enUsCulture); + object workbook = ComInterop.Util.TypeAdapter.GetProperty("Workbook", obj); + //object workbook = obj.GetType().InvokeMember("Workbook", BindingFlags.GetProperty, null, obj, null, _enUsCulture); + app = ComInterop.Util.TypeAdapter.GetProperty("Application", workbook); + //app = workbook.GetType().InvokeMember("Application", BindingFlags.GetProperty, null, workbook, null, _enUsCulture); // WARNING: The Application object returning from here can be problematic: // * It is a "sandbox" view of the Application that cannot Run macros or change workbooks @@ -484,7 +495,8 @@ private static Microsoft.Office.Interop.Excel.Application GetApplicationFromWind } finally { - Marshal.ReleaseComObject(obj); + ComInterop.Util.TypeAdapter.ReleaseObject(obj); + //Marshal.ReleaseComObject(obj); } // Continue enumeration? Only if the app is not yet found and protected flag not set. diff --git a/Source/ExcelDna.Integration/ExcelCommandBars.cs b/Source/ExcelDna.Integration/ExcelCommandBars.cs index 1532146c..2dbd918e 100644 --- a/Source/ExcelDna.Integration/ExcelCommandBars.cs +++ b/Source/ExcelDna.Integration/ExcelCommandBars.cs @@ -63,7 +63,8 @@ public static class ExcelCommandBarUtil // Helper to call Application.CommandBars public static CommandBars GetCommandBars() { - Application excelApp = new Application(NativeAOT.IsActive ? NativeAOT.ExcelApplication : ExcelDnaUtil.Application); + Application excelApp = new Application(ExcelDnaUtil.ApplicationObject); + //Application excelApp = new Application(NativeAOT.IsActive ? NativeAOT.ExcelApplication : ExcelDnaUtil.Application); return excelApp.CommandBars; } From 83482d11553648261680619d0cc5181da1292b7b Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sat, 15 Mar 2025 18:19:17 +0500 Subject: [PATCH 29/60] Implemented TypeAdapter.Is using QueryInterface. --- .../ComApi/ComClass.cs | 28 --- .../ComApi/ExcelObject.cs | 221 ------------------ .../ComApi/ICommandBarControl.cs | 33 --- .../ComObject.cs | 152 ++++++++++++ .../ExcelDna.COMWrappers.NativeAOT/Excel.cs | 115 --------- .../OpenWindowGetter.cs | 53 ----- .../TypeAdapter.cs | 46 +--- .../Types/Managed/Variant.cs | 1 + .../Types/Marshalling/Variant.cs | 1 + Source/ExcelDna.COMWrappers.NativeAOT/Util.cs | 23 -- Source/ExcelDna.Integration/NativeAOT.cs | 1 - .../Generator.cs | 1 - 12 files changed, 162 insertions(+), 513 deletions(-) delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ComClass.cs delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ExcelObject.cs delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ICommandBarControl.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComObject.cs delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Excel.cs delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/OpenWindowGetter.cs delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Util.cs diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ComClass.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ComClass.cs deleted file mode 100644 index 5a0b6853..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ComClass.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Addin.Types.Unmanaged; -using System.Runtime.InteropServices; - -namespace Addin.ComApi; - -public partial class ComClass -{ - [LibraryImport("ole32.dll")] - public static partial int CoCreateInstance( - ref Guid rclsid, - nint pUnkOuter, - ClsCtx dwClsContext, - ref Guid riid, - out IDispatch ppv - ); - - public static IDispatch Create(Guid clsid, ClsCtx server) - { - var guid = typeof(IDispatch).GUID; - - int hr = CoCreateInstance(ref clsid, nint.Zero, server, ref guid, out IDispatch obj); - if (hr < 0) - { - Marshal.ThrowExceptionForHR(hr); - } - return obj; - } -} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ExcelObject.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ExcelObject.cs deleted file mode 100644 index 1ea9c3e0..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ExcelObject.cs +++ /dev/null @@ -1,221 +0,0 @@ -using Addin.Types.Managed; -using System.Dynamic; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; -using static Addin.Types.Unmanaged.ComConstants; -using Unmanaged = Addin.Types.Unmanaged; - -namespace Addin.ComApi; - -public class ExcelObject : DynamicObject -{ - public IDispatch _interfacePtr; - Guid emptyGuid = Guid.Empty; - bool _verbose; - - public ExcelObject(IDispatch? interfacePtr = null) - { - if (interfacePtr != null) - { - _interfacePtr = interfacePtr; - return; - } - - //// The CLSID for Excel.Application (COMView.exe->CLSID table) - //var clsid = new Guid("{00024500-0000-0000-C000-000000000046}"); - - //// COMView.exe -> CLSID table -> Type column - //var server = Unmanaged.ClsCtx.CLSCTX_LOCAL_SERVER; - - //_interfacePtr = ComClass.Create(clsid, server); - } - - public object? GetProperty(string name) - { - DispParams dispParams = new(); - - return InvokeWrapper(name, INVOKEKIND.INVOKE_PROPERTYGET, dispParams); - } - - public bool HasProperty(string name) - { - try - { - GetDispIDs(name); - return true; - } - catch - { - } - - return false; - } - - public override bool TryGetMember(GetMemberBinder binder, out object? result) - { - DispParams dispParams = new(); - - result = InvokeWrapper(binder.Name, INVOKEKIND.INVOKE_PROPERTYGET, dispParams); - - return true; - } - - public override bool TrySetMember(SetMemberBinder binder, object value) - { - var dispParams = new DispParams - { - rgvarg = [new Variant(value)], - rgdispidNamedArgs = DISPID_PROPERTYPUT, - cArgs = 1, - cNamedArgs = 1 - }; - - InvokeWrapper(binder.Name, INVOKEKIND.INVOKE_PROPERTYPUT, dispParams); - - return true; - } - - public void SetProperty(string name, object value) - { - var dispParams = new DispParams - { - rgvarg = [new Variant(value)], - rgdispidNamedArgs = DISPID_PROPERTYPUT, - cArgs = 1, - cNamedArgs = 1 - }; - - InvokeWrapper(name, INVOKEKIND.INVOKE_PROPERTYPUT, dispParams); - } - - public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object? result) - { - var index = (int)indexes[0]; - - var dispParams = new DispParams - { - rgvarg = [new Variant(index)], - rgdispidNamedArgs = 0, - cArgs = 1, - cNamedArgs = 0 - }; - - result = InvokeWrapper("Item", INVOKEKIND.INVOKE_PROPERTYGET, dispParams); - - return true; - } - - public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) - { - throw new NotImplementedException(); - } - - public override bool TryInvokeMember( - InvokeMemberBinder binder, - object[] args, - out object result - ) - { - //DispParams dispParams = new(); - - Variant[] a = new Variant[args.Length]; - for (int i = 0; i < args.Length; ++i) - a[i] = new Variant(args[i]); - - var dispParams = new DispParams - { - rgvarg = a, - rgdispidNamedArgs = 0, - cArgs = a.Length, - cNamedArgs = 0 - }; - - result = InvokeWrapper(binder.Name, INVOKEKIND.INVOKE_FUNC, dispParams); - - return true; - } - - public object InvokeMember( - string name, - object[] args -) - { - //DispParams dispParams = new(); - - Variant[] a = new Variant[args.Length]; - for (int i = 0; i < args.Length; ++i) - { - object? o = args[i].GetType().IsEnum ? (int)args[i] : args[i]; - - System.Diagnostics.Trace.WriteLine("[InvokeMember] " + name + " " + o?.GetType().ToString()); - a[i] = new Variant(o); - } - - var dispParams = new DispParams - { - rgvarg = a, - rgdispidNamedArgs = 0, - cArgs = a.Length, - cNamedArgs = 0 - }; - - return InvokeWrapper(name, INVOKEKIND.INVOKE_FUNC, dispParams); - } - - public object InvokeWrapper(string propName, INVOKEKIND kind, DispParams dispParams) - { - var dispIds = GetDispIDs(propName); - - ExcepInfo pExcepInfo = new(); - Variant pVarResult = new(); - uint puArgErr = 0; - - var hr = _interfacePtr.Invoke( - dispIds[0], - emptyGuid, - LOCALE_USER_DEFAULT, - kind, - ref dispParams, - ref pVarResult, - ref pExcepInfo, - ref puArgErr - ); - - Marshal.ThrowExceptionForHR(hr); - - // Found an IDispatch object - swap current instance - if (pVarResult.Value is IDispatch interfacePtr) - { - return new ExcelObject(interfacePtr); - } - - return pVarResult.Value; - } - - private int[] GetDispIDs(string propName) - { - var names = new string[] { propName }; - - var dispIds = new int[names.Length]; - var hr = _interfacePtr.GetIDsOfNames( - ref emptyGuid, - names, - (uint)names.Length, - LOCALE_USER_DEFAULT, - dispIds - ); - - if (hr < 0) - { - Marshal.ThrowExceptionForHR(hr); - } - - if (_verbose) - { - for (int i = 0; i < names.Length; i++) - Console.WriteLine($"{names[i]}: {dispIds[i]}"); - } - - return dispIds; - } -} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ICommandBarControl.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ICommandBarControl.cs deleted file mode 100644 index 436e563b..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/ICommandBarControl.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; -using System.Runtime.InteropServices.Marshalling; -using Managed = Addin.Types.Managed; -using Marshalling = Addin.Types.Marshalling; - -namespace Addin.ComApi; - -[GeneratedComInterface] -[Guid("000C030E-0000-0000-C000-000000000046")] -public partial interface ICommandBarButton -{ -} - -[GeneratedComInterface] -[Guid("000C030A-0000-0000-C000-000000000046")] -public partial interface ICommandBarPopup -{ -} - -[GeneratedComInterface] -[Guid("000C030C-0000-0000-C000-000000000046")] -public partial interface ICommandBarComboBox -{ -} - -//[GeneratedComInterface] -//[Guid("000C0306-0000-0000-C000-000000000046")] -//public partial interface ICommandBarControls -//{ -// [PreserveSig] -// object Add(object Type, object Id, object Parameter, object Before, object Temporary); -//} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComObject.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComObject.cs new file mode 100644 index 00000000..d284a1ac --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComObject.cs @@ -0,0 +1,152 @@ +using Addin.ComApi; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using System.Runtime.InteropServices.ComTypes; + +namespace ExcelDna.COMWrappers.NativeAOT +{ + internal class ComObject + { + private IntPtr pUnk; + private IDispatch? dispatch; + private Guid emptyGuid = Guid.Empty; + + private const int LOCALE_USER_DEFAULT = 0x0400; + private const int DISPID_PROPERTYPUT = -3; + + + public ComObject(IntPtr pUnk) + { + this.pUnk = pUnk; + + ComWrappers cw = new StrategyBasedComWrappers(); + dispatch = cw.GetOrCreateObjectForComInstance(pUnk, CreateObjectFlags.None) as IDispatch; + } + + public bool HasProperty(string name) + { + try + { + GetDispIDs(name); + return true; + } + catch + { + } + + return false; + } + + public object? GetProperty(string name) + { + Addin.Types.Managed.DispParams dispParams = new(); + + return InvokeWrapper(name, INVOKEKIND.INVOKE_PROPERTYGET, dispParams); + } + + public void SetProperty(string name, object value) + { + var dispParams = new Addin.Types.Managed.DispParams + { + rgvarg = [new Addin.Types.Managed.Variant(value)], + rgdispidNamedArgs = DISPID_PROPERTYPUT, + cArgs = 1, + cNamedArgs = 1 + }; + + InvokeWrapper(name, INVOKEKIND.INVOKE_PROPERTYPUT, dispParams); + } + + public object? GetIndex(int i) + { + var index = i; + + var dispParams = new Addin.Types.Managed.DispParams + { + rgvarg = [new Addin.Types.Managed.Variant(index)], + rgdispidNamedArgs = 0, + cArgs = 1, + cNamedArgs = 0 + }; + + return InvokeWrapper("Item", INVOKEKIND.INVOKE_PROPERTYGET, dispParams); + } + + public object? Invoke(string name, object[] args) + { + Addin.Types.Managed.Variant[] a = new Addin.Types.Managed.Variant[args.Length]; + for (int i = 0; i < args.Length; ++i) + { + object? o = args[i].GetType().IsEnum ? (int)args[i] : args[i]; + a[i] = new Addin.Types.Managed.Variant(o); + } + + var dispParams = new Addin.Types.Managed.DispParams + { + rgvarg = a, + rgdispidNamedArgs = 0, + cArgs = a.Length, + cNamedArgs = 0 + }; + + return InvokeWrapper(name, INVOKEKIND.INVOKE_FUNC, dispParams); + } + + public unsafe bool HasInterface(ref Guid guid) + { + IIUnknownStrategy iUnknownStrategy = StrategyBasedComWrappers.DefaultIUnknownStrategy; + iUnknownStrategy.QueryInterface(pUnk.ToPointer(), in guid, out void* ppObj); + return ppObj != null; + } + + private int[] GetDispIDs(string propName) + { + var names = new string[] { propName }; + + var dispIds = new int[names.Length]; + var hr = dispatch!.GetIDsOfNames( + ref emptyGuid, + names, + (uint)names.Length, + LOCALE_USER_DEFAULT, + dispIds + ); + + if (hr < 0) + { + Marshal.ThrowExceptionForHR(hr); + } + + return dispIds; + } + + private object? InvokeWrapper(string propName, INVOKEKIND kind, Addin.Types.Managed.DispParams dispParams) + { + var dispIds = GetDispIDs(propName); + + Addin.Types.Managed.ExcepInfo pExcepInfo = new(); + Addin.Types.Managed.Variant pVarResult = new(); + uint puArgErr = 0; + + var hr = dispatch!.Invoke( + dispIds[0], + emptyGuid, + LOCALE_USER_DEFAULT, + kind, + ref dispParams, + ref pVarResult, + ref pExcepInfo, + ref puArgErr + ); + + Marshal.ThrowExceptionForHR(hr); + + if (pVarResult.Value is IDispatch interfacePtr) + { + return new ComObject(pVarResult.DispVal); + } + + return pVarResult.Value; + } + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Excel.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Excel.cs deleted file mode 100644 index a2e2f2f1..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Excel.cs +++ /dev/null @@ -1,115 +0,0 @@ -using Addin.ComApi; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; -using System.Text; -using System.Threading.Tasks; - -namespace ExcelDna.COMWrappers.NativeAOT -{ - internal class Excel - { - public static object? GetApplicationFromWindow(IntPtr hWndMain) - { - object? result = null; - StringBuilder cname = new StringBuilder(256); - - EnumChildWindows(hWndMain, delegate (IntPtr hWndEnum, IntPtr param) - { - // Check the window class - GetClassNameW(hWndEnum, cname, cname.Capacity); - - System.Diagnostics.Trace.WriteLine("[GetApplicationFromWindow cname ]" + cname.ToString()); - - - if (cname.ToString() != "EXCEL7") - // Not a workbook window, continue enumerating - return true; - - System.Diagnostics.Trace.WriteLine("[GetApplicationFromWindow got EXCEL7]"); - - - IntPtr pUnk = IntPtr.Zero; - int hr = AccessibleObjectFromWindow(hWndEnum, OBJID_NATIVEOM, IID_IDispatchBytes, ref pUnk); - if (hr != 0) - { - // Window does not implement the IID, continue enumerating - return true; - } - - System.Diagnostics.Trace.WriteLine("[GetApplicationFromWindow got pUnk]"); - - // Marshal to .NET, then call .Application - //object obj = Marshal.GetObjectForIUnknown(pUnk); - //Console.WriteLine("GetApplicationFromWindow GetObjectForIUnknown"); - - ComWrappers cw = new StrategyBasedComWrappers(); - //object obj = cw.GetOrCreateObjectForComInstance(pUnk, CreateObjectFlags.None); - //ComObject co = obj; - - //var t = obj.GetType(); - IDispatch foo = (IDispatch)cw.GetOrCreateObjectForComInstance(pUnk, CreateObjectFlags.None); - //foo. - //IntPtr app = foo.get_Application2xx(); - - //hr = foo.GetTypeInfoCount(out uint tcount); - - //const int LcidUsEnglish = 0x0409; - //string[] names = new string[1]; - //int[] ids = new int[1]; - //names[0] = "Application"; - //Guid g = Guid.Empty; - //hr = foo.GetIDsOfNames(ref g, names, 1, LcidUsEnglish, ids); - - //int[] i1 = new int[4]; - //IntPtr i2 = 0; - //hr = foo.Invoke(ids[0], ref g, LcidUsEnglish, 2, i1, out IntPtr pVarResult, ref i2, out uint perr); - - var excelWindowWrapper = new ExcelObject(foo); - - var app = excelWindowWrapper.GetProperty("Application"); - if (app is ExcelObject excelObject) - result = excelObject._interfacePtr; - else - result = app; - - //dynamic dapp = app; - //var commandBars = dapp.CommandBars; - //var worksheetBar = commandBars[1]; - //var controls = worksheetBar.Controls; - - //string menuName = "ConsoleApp1 Menu"; - //var menu = controls.AddPopup(menuName); - //menu.Caption = menuName; - - //Console.WriteLine("GetApplicationFromWindow GetOrCreateObjectForComInstance"); - - - return result == null; - }, IntPtr.Zero); - - System.Diagnostics.Trace.WriteLine("[GetApplicationFromWindow result]" + result?.GetType().ToString()); - - return result; - } - - private delegate bool EnumWindowsCallback(IntPtr hwnd, /*ref*/ IntPtr param); - - [DllImport("user32.dll")] - private static extern bool EnumChildWindows(IntPtr hWndParent, EnumWindowsCallback callback, /*ref*/ IntPtr param); - - [DllImport("user32.dll")] - private static extern int GetClassNameW(IntPtr hwnd, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder buf, int nMaxCount); - - [DllImport("Oleacc.dll")] - private static extern int AccessibleObjectFromWindow( - IntPtr hwnd, uint dwObjectID, byte[] riid, - ref IntPtr ptr /*ppUnk*/); - - private const uint OBJID_NATIVEOM = 0xFFFFFFF0; - - private static readonly byte[] IID_IDispatchBytes = new Guid("{00020400-0000-0000-C000-000000000046}").ToByteArray(); - } -} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/OpenWindowGetter.cs b/Source/ExcelDna.COMWrappers.NativeAOT/OpenWindowGetter.cs deleted file mode 100644 index 9e67d244..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/OpenWindowGetter.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Runtime.InteropServices; -using System.Text; -using HWND = System.IntPtr; - -namespace ExcelDna.COMWrappers.NativeAOT -{ - /// Contains functionality to get all the open windows. - public static class OpenWindowGetter - { - /// Returns a dictionary that contains the handle and title of all the open windows. - /// A dictionary that contains the handle and title of all the open windows. - public static IDictionary GetOpenWindows() - { - HWND shellWindow = GetShellWindow(); - Dictionary windows = new Dictionary(); - - EnumWindows(delegate (HWND hWnd, int lParam) - { - if (hWnd == shellWindow) return true; - if (!IsWindowVisible(hWnd)) return true; - - int length = GetWindowTextLength(hWnd); - if (length == 0) return true; - - StringBuilder builder = new StringBuilder(length); - GetWindowText(hWnd, builder, length + 1); - - windows[hWnd] = builder.ToString(); - return true; - - }, 0); - - return windows; - } - - private delegate bool EnumWindowsProc(HWND hWnd, int lParam); - - [DllImport("USER32.DLL")] - private static extern bool EnumWindows(EnumWindowsProc enumFunc, int lParam); - - [DllImport("USER32.DLL")] - private static extern int GetWindowText(HWND hWnd, StringBuilder lpString, int nMaxCount); - - [DllImport("USER32.DLL")] - private static extern int GetWindowTextLength(HWND hWnd); - - [DllImport("USER32.DLL")] - private static extern bool IsWindowVisible(HWND hWnd); - - [DllImport("USER32.DLL")] - private static extern IntPtr GetShellWindow(); - } -} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs b/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs index b22adbf7..896ce5e7 100644 --- a/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs +++ b/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs @@ -1,7 +1,4 @@ -using Addin.ComApi; -using ExcelDna.ComInterop; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; +using ExcelDna.ComInterop; namespace ExcelDna.COMWrappers.NativeAOT { @@ -9,58 +6,32 @@ public class TypeAdapter : IType { public object GetProperty(string name, object comObject) { - var excelWindowWrapper = new ExcelObject(comObject as IDispatch); - object? result = excelWindowWrapper.GetProperty(name); - if (result is ExcelObject excelObject) - return excelObject._interfacePtr; - - return result!; + return (comObject as ComObject)!.GetProperty(name)!; } public object GetIndex(int i, object comObject) { - var excelWindowWrapper = new ExcelObject(comObject as IDispatch); - excelWindowWrapper.TryGetIndex(null, new object[] { i }, out object? result); - if (result is ExcelObject excelObject) - return excelObject._interfacePtr; - - return result!; + return (comObject as ComObject)!.GetIndex(i)!; } public bool Is(ref Guid guid, object comObject) { - if (guid == new Guid("000C030E-0000-0000-C000-000000000046")) - return comObject is ICommandBarButton; - - if (guid == new Guid("000C030A-0000-0000-C000-000000000046")) - return comObject is ICommandBarPopup; - - if (guid == new Guid("000C030C-0000-0000-C000-000000000046")) - return comObject is ICommandBarComboBox; - - throw new NotImplementedException(); + return (comObject as ComObject)!.HasInterface(ref guid); } public object Invoke(string name, object[] args, object comObject) { - var excelWindowWrapper = new ExcelObject(comObject as IDispatch); - object? result = excelWindowWrapper.InvokeMember(name, args); - if (result is ExcelObject excelObject) - return excelObject._interfacePtr; - - return result!; + return (comObject as ComObject)!.Invoke(name, args)!; } public void SetProperty(string name, object value, object comObject) { - var excelWindowWrapper = new ExcelObject(comObject as IDispatch); - excelWindowWrapper.SetProperty(name, value); + (comObject as ComObject)!.SetProperty(name, value); } public object GetObject(IntPtr pUnk) { - ComWrappers cw = new StrategyBasedComWrappers(); - return cw.GetOrCreateObjectForComInstance(pUnk, CreateObjectFlags.None); + return new ComObject(pUnk); } public void ReleaseObject(object comObject) @@ -69,8 +40,7 @@ public void ReleaseObject(object comObject) public bool HasProperty(string name, object comObject) { - var excelWindowWrapper = new ExcelObject(comObject as IDispatch); - return excelWindowWrapper.HasProperty(name); + return (comObject as ComObject)!.HasProperty(name); } } } diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/Variant.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/Variant.cs index f0c3bafa..ec2ac194 100644 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/Variant.cs +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/Variant.cs @@ -8,4 +8,5 @@ public Variant(object? value) } public object? Value { get; set; } + public IntPtr DispVal { get; set; } } diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Variant.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Variant.cs index b408dd1a..d3225ef3 100644 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Variant.cs +++ b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Variant.cs @@ -66,6 +66,7 @@ public static unsafe Managed.Variant ConvertToManaged(Unmanaged.Variant unmanage Value = ComInterfaceMarshaller.ConvertToManaged( (void*)unmanaged.pdispVal ), + DispVal = unmanaged.pdispVal }, VariantType.VT_EMPTY => new Managed.Variant { }, VariantType.VT_NULL => new Managed.Variant { }, diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Util.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Util.cs deleted file mode 100644 index 5dbac5b3..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Util.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace ExcelDna.COMWrappers.NativeAOT -{ - public static class Util - { - public static object? GetExcelApplication() - { - foreach (var w in OpenWindowGetter.GetOpenWindows()) - { - if (w.Value.EndsWith("Excel")) - return GetExcelObject(w.Key); - //Console.WriteLine(w.Value); - - } - - return null; - } - - static object? GetExcelObject(System.IntPtr w) - { - return Excel.GetApplicationFromWindow(w); - } - } -} diff --git a/Source/ExcelDna.Integration/NativeAOT.cs b/Source/ExcelDna.Integration/NativeAOT.cs index ee11ed3c..26f7d80a 100644 --- a/Source/ExcelDna.Integration/NativeAOT.cs +++ b/Source/ExcelDna.Integration/NativeAOT.cs @@ -6,7 +6,6 @@ namespace ExcelDna.Integration public class NativeAOT { public static bool IsActive { get; set; } - public static object ExcelApplication { get; set; } public static ComInterop.IType TypeAdapter { get; set; } public static List MethodsForRegistration { get; } = new List(); diff --git a/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs b/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs index 50bd786a..71b640b4 100644 --- a/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs +++ b/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs @@ -29,7 +29,6 @@ public unsafe class AddInInitialize public static short Initialize(void* xlAddInExportInfoAddress, void* hModuleXll, void* pPathXLL, byte disableAssemblyContextUnload, void* pTempDirPath) { ExcelDna.Integration.NativeAOT.IsActive = true; - ExcelDna.Integration.NativeAOT.ExcelApplication = ExcelDna.COMWrappers.NativeAOT.Util.GetExcelApplication()!; ExcelDna.Integration.NativeAOT.TypeAdapter = new ExcelDna.COMWrappers.NativeAOT.TypeAdapter(); [ADDINS] From c388ebf0393a0ad8dd5a66342ad91745eab30de6 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sat, 22 Mar 2025 14:44:52 +0500 Subject: [PATCH 30/60] Cleaned and refactored ExcelDna.COMWrappers.NativeAOT project. --- .../ComApi/IDispatch.cs | 39 ---- .../ComInterfaces/ArrayMarshaller.cs | 24 ++ .../ComInterfaces/DispParams.cs | 10 + .../ComInterfaces/DispParamsMarshaller.cs | 37 ++++ .../ComInterfaces/DispParamsNative.cs | 13 ++ .../DispatchObject.cs} | 63 ++---- .../ComInterfaces/ExcepInfo.cs | 54 +++++ .../ComInterfaces/ExcepInfoMarshaller.cs | 46 ++++ .../ComInterfaces/ExcepInfoNative.cs | 18 ++ .../ComInterfaces/IDispatch.cs | 38 ++++ .../ComInterfaces/UnknownObject.cs | 20 ++ .../ComInterfaces/Variant.cs | 12 + .../ComInterfaces/VariantBoolNative.cs | 8 + .../ComInterfaces/VariantMarshaller.cs | 77 +++++++ .../ComInterfaces/VariantNative.cs | 209 ++++++++++++++++++ .../ComInterfaces/VariantTypeNative.cs | 58 +++++ .../TypeAdapter.cs | 15 +- .../Types/Managed/DispParams.cs | 9 - .../Types/Managed/ExcepInfo.cs | 53 ----- .../Types/Managed/Variant.cs | 12 - .../Types/Managed/XlOper.cs | 60 ----- .../Types/Marshalling/Array.cs | 31 --- .../Types/Marshalling/DispParams.cs | 36 --- .../Types/Marshalling/ExcepInfo.cs | 45 ---- .../Types/Marshalling/Variant.cs | 76 ------- .../Types/Unmanaged/ClsCtx.cs | 33 --- .../Types/Unmanaged/ComConstants.cs | 9 - .../Types/Unmanaged/DispParams.cs | 12 - .../Types/Unmanaged/ExcelConstants.cs | 100 --------- .../Types/Unmanaged/ExcepInfo.cs | 17 -- .../Types/Unmanaged/Variant.cs | 208 ----------------- .../Types/Unmanaged/VariantBool.cs | 7 - .../Types/Unmanaged/VariantType.cs | 57 ----- .../Types/Unmanaged/XlOper12.cs | 178 --------------- 34 files changed, 653 insertions(+), 1031 deletions(-) delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComApi/IDispatch.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/ArrayMarshaller.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispParams.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispParamsMarshaller.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispParamsNative.cs rename Source/ExcelDna.COMWrappers.NativeAOT/{ComObject.cs => ComInterfaces/DispatchObject.cs} (59%) create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/ExcepInfo.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/ExcepInfoMarshaller.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/ExcepInfoNative.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/IDispatch.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/UnknownObject.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/Variant.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/VariantBoolNative.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/VariantMarshaller.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/VariantNative.cs create mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/VariantTypeNative.cs delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/DispParams.cs delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/ExcepInfo.cs delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/Variant.cs delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/XlOper.cs delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Array.cs delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/DispParams.cs delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/ExcepInfo.cs delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Variant.cs delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ClsCtx.cs delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ComConstants.cs delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/DispParams.cs delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ExcelConstants.cs delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ExcepInfo.cs delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/Variant.cs delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/VariantBool.cs delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/VariantType.cs delete mode 100644 Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/XlOper12.cs diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/IDispatch.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/IDispatch.cs deleted file mode 100644 index c8998601..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/ComApi/IDispatch.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; -using System.Runtime.InteropServices.Marshalling; -using Managed = Addin.Types.Managed; -using Marshalling = Addin.Types.Marshalling; - -namespace Addin.ComApi; - -[GeneratedComInterface] -[Guid("00020400-0000-0000-C000-000000000046")] // The IID for IDispatch -public partial interface IDispatch -{ - [PreserveSig] - int GetTypeInfoCount(out uint pctinfo); - - [PreserveSig] - int GetTypeInfo(uint iTInfo, uint lcid, out nint ppTInfo); - - [PreserveSig] - int GetIDsOfNames( - ref Guid riid, - [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] rgszNames, - uint cNames, - uint lcid, - [MarshalAs(UnmanagedType.LPArray)] int[] rgDispId - ); - - [PreserveSig] - int Invoke( - int dispIdMember, - Guid riid, - uint lcid, - INVOKEKIND wFlags, - [MarshalUsing(typeof(Marshalling.DispParams))] ref Managed.DispParams pDispParams, - [MarshalUsing(typeof(Marshalling.Variant))] ref Managed.Variant pVarResult, - [MarshalUsing(typeof(Marshalling.ExcepInfo))] ref Managed.ExcepInfo pExcepInfo, - ref uint puArgErr - ); -} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/ArrayMarshaller.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/ArrayMarshaller.cs new file mode 100644 index 00000000..d46a18e2 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/ArrayMarshaller.cs @@ -0,0 +1,24 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace ExcelDna.COMWrappers.NativeAOT.ComInterfaces +{ + internal static class ArrayMarshaller + { + public unsafe static nint ArrayToPtr(T[] str) + { + return (nint)Unsafe.AsPointer(ref MemoryMarshal.GetArrayDataReference(str)); + } + + public static T[] PtrToArray(nint str, int len) + { + var size = Marshal.SizeOf(); + var ret = new T[len]; + for (int i = 0; i < len; ++i) + { + ret[i] = Marshal.PtrToStructure(nint.Add(str, i * size))!; + } + return ret; + } + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispParams.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispParams.cs new file mode 100644 index 00000000..a0e943ab --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispParams.cs @@ -0,0 +1,10 @@ +namespace ExcelDna.COMWrappers.NativeAOT.ComInterfaces +{ + internal struct DispParams + { + public int cArgs; + public int cNamedArgs; + public int rgdispidNamedArgs; + public Variant[] rgvarg; + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispParamsMarshaller.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispParamsMarshaller.cs new file mode 100644 index 00000000..8ed9ae91 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispParamsMarshaller.cs @@ -0,0 +1,37 @@ +using System.Runtime.InteropServices.Marshalling; + +namespace ExcelDna.COMWrappers.NativeAOT.ComInterfaces +{ + [CustomMarshaller(typeof(DispParams), MarshalMode.Default, typeof(DispParamsMarshaller))] + internal static class DispParamsMarshaller + { + public static unsafe DispParamsNative ConvertToUnmanaged(DispParams managed) + { + return new DispParamsNative + { + cArgs = managed.cArgs, + cNamedArgs = managed.cNamedArgs, + rgdispidNamedArgs = &managed.rgdispidNamedArgs, + rgvarg = + managed.rgvarg != null + ? ArrayMarshaller.ArrayToPtr(managed.rgvarg.Reverse().Select(VariantMarshaller.ConvertToUnmanaged).ToArray()) + : nint.Zero + }; + } + + public static unsafe DispParams ConvertToManaged(DispParamsNative unmanaged) + { + return new DispParams + { + cArgs = unmanaged.cArgs, + cNamedArgs = unmanaged.cNamedArgs, + rgdispidNamedArgs = *unmanaged.rgdispidNamedArgs, + rgvarg = ArrayMarshaller + .PtrToArray(unmanaged.rgvarg, unmanaged.cArgs) + .Select(VariantMarshaller.ConvertToManaged) + .Reverse() + .ToArray(), + }; + } + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispParamsNative.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispParamsNative.cs new file mode 100644 index 00000000..d79daced --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispParamsNative.cs @@ -0,0 +1,13 @@ +using System.Runtime.InteropServices; + +namespace ExcelDna.COMWrappers.NativeAOT.ComInterfaces +{ + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct DispParamsNative + { + public nint rgvarg; + public int* rgdispidNamedArgs; + public int cArgs; + public int cNamedArgs; + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComObject.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispatchObject.cs similarity index 59% rename from Source/ExcelDna.COMWrappers.NativeAOT/ComObject.cs rename to Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispatchObject.cs index d284a1ac..26ef7d23 100644 --- a/Source/ExcelDna.COMWrappers.NativeAOT/ComObject.cs +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispatchObject.cs @@ -1,26 +1,25 @@ -using Addin.ComApi; -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; using System.Runtime.InteropServices.ComTypes; -namespace ExcelDna.COMWrappers.NativeAOT +namespace ExcelDna.COMWrappers.NativeAOT.ComInterfaces { - internal class ComObject + internal class DispatchObject : UnknownObject { - private IntPtr pUnk; - private IDispatch? dispatch; + private IDispatch dispatch; private Guid emptyGuid = Guid.Empty; private const int LOCALE_USER_DEFAULT = 0x0400; private const int DISPID_PROPERTYPUT = -3; - - public ComObject(IntPtr pUnk) + public DispatchObject(IntPtr unknown) : base(unknown) { - this.pUnk = pUnk; - ComWrappers cw = new StrategyBasedComWrappers(); - dispatch = cw.GetOrCreateObjectForComInstance(pUnk, CreateObjectFlags.None) as IDispatch; + IDispatch? dispatch = cw.GetOrCreateObjectForComInstance(P, CreateObjectFlags.None) as IDispatch; + if (dispatch == null) + throw new ArgumentException(); + + this.dispatch = dispatch; } public bool HasProperty(string name) @@ -39,16 +38,16 @@ public bool HasProperty(string name) public object? GetProperty(string name) { - Addin.Types.Managed.DispParams dispParams = new(); + DispParams dispParams = new(); return InvokeWrapper(name, INVOKEKIND.INVOKE_PROPERTYGET, dispParams); } public void SetProperty(string name, object value) { - var dispParams = new Addin.Types.Managed.DispParams + var dispParams = new DispParams { - rgvarg = [new Addin.Types.Managed.Variant(value)], + rgvarg = [new Variant(value)], rgdispidNamedArgs = DISPID_PROPERTYPUT, cArgs = 1, cNamedArgs = 1 @@ -61,9 +60,9 @@ public void SetProperty(string name, object value) { var index = i; - var dispParams = new Addin.Types.Managed.DispParams + var dispParams = new DispParams { - rgvarg = [new Addin.Types.Managed.Variant(index)], + rgvarg = [new Variant(index)], rgdispidNamedArgs = 0, cArgs = 1, cNamedArgs = 0 @@ -74,14 +73,9 @@ public void SetProperty(string name, object value) public object? Invoke(string name, object[] args) { - Addin.Types.Managed.Variant[] a = new Addin.Types.Managed.Variant[args.Length]; - for (int i = 0; i < args.Length; ++i) - { - object? o = args[i].GetType().IsEnum ? (int)args[i] : args[i]; - a[i] = new Addin.Types.Managed.Variant(o); - } + Variant[] a = args.Select(i => new Variant(i)).ToArray(); - var dispParams = new Addin.Types.Managed.DispParams + var dispParams = new DispParams { rgvarg = a, rgdispidNamedArgs = 0, @@ -92,13 +86,6 @@ public void SetProperty(string name, object value) return InvokeWrapper(name, INVOKEKIND.INVOKE_FUNC, dispParams); } - public unsafe bool HasInterface(ref Guid guid) - { - IIUnknownStrategy iUnknownStrategy = StrategyBasedComWrappers.DefaultIUnknownStrategy; - iUnknownStrategy.QueryInterface(pUnk.ToPointer(), in guid, out void* ppObj); - return ppObj != null; - } - private int[] GetDispIDs(string propName) { var names = new string[] { propName }; @@ -112,20 +99,17 @@ private int[] GetDispIDs(string propName) dispIds ); - if (hr < 0) - { - Marshal.ThrowExceptionForHR(hr); - } + Marshal.ThrowExceptionForHR(hr); return dispIds; } - private object? InvokeWrapper(string propName, INVOKEKIND kind, Addin.Types.Managed.DispParams dispParams) + private object? InvokeWrapper(string propName, INVOKEKIND kind, DispParams dispParams) { var dispIds = GetDispIDs(propName); - Addin.Types.Managed.ExcepInfo pExcepInfo = new(); - Addin.Types.Managed.Variant pVarResult = new(); + ExcepInfo pExcepInfo = new(); + Variant pVarResult = new(); uint puArgErr = 0; var hr = dispatch!.Invoke( @@ -141,11 +125,6 @@ ref puArgErr Marshal.ThrowExceptionForHR(hr); - if (pVarResult.Value is IDispatch interfacePtr) - { - return new ComObject(pVarResult.DispVal); - } - return pVarResult.Value; } } diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/ExcepInfo.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/ExcepInfo.cs new file mode 100644 index 00000000..e556b7e8 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/ExcepInfo.cs @@ -0,0 +1,54 @@ +namespace ExcelDna.COMWrappers.NativeAOT.ComInterfaces +{ + internal struct ExcepInfo + { + // + // Summary: + // Describes the error intended for the customer. + public string bstrDescription; + + // + // Summary: + // Contains the fully-qualified drive, path, and file name of a Help file that contains + // more information about the error. + public string bstrHelpFile; + + // + // Summary: + // Indicates the name of the source of the exception. Typically, this is an application + // name. + public string bstrSource; + + // + // Summary: + // Indicates the Help context ID of the topic within the Help file. + public int dwHelpContext; + + // + // Summary: + // Represents a pointer to a function that takes an System.Runtime.InteropServices.EXCEPINFO + // structure as an argument and returns an HRESULT value. If deferred fill-in is + // not desired, this field is set to null. + public nint pfnDeferredFillIn; + + // + // Summary: + // This field is reserved; it must be set to null. + public nint pvReserved; + + // + // Summary: + // A return value describing the error. + public int scode; + + // + // Summary: + // Represents an error code identifying the error. + public short wCode; + + // + // Summary: + // This field is reserved; it must be set to 0. + public short wReserved; + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/ExcepInfoMarshaller.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/ExcepInfoMarshaller.cs new file mode 100644 index 00000000..382f2ef9 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/ExcepInfoMarshaller.cs @@ -0,0 +1,46 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace ExcelDna.COMWrappers.NativeAOT.ComInterfaces +{ + [CustomMarshaller(typeof(ExcepInfo), MarshalMode.Default, typeof(ExcepInfoMarshaller))] + internal static class ExcepInfoMarshaller + { + public static ExcepInfoNative ConvertToUnmanaged(ExcepInfo managed) + { + return new ExcepInfoNative + { + bstrDescription = Marshal.StringToBSTR(managed.bstrDescription), + bstrHelpFile = Marshal.StringToBSTR(managed.bstrHelpFile), + bstrSource = Marshal.StringToBSTR(managed.bstrSource), + dwHelpContext = managed.dwHelpContext, + pfnDeferredFillIn = managed.pfnDeferredFillIn, + pvReserved = managed.pvReserved, + scode = managed.scode, + wCode = managed.wCode, + wReserved = managed.wReserved, + }; + } + + public static ExcepInfo ConvertToManaged(ExcepInfoNative unmanaged) + { + return new ExcepInfo + { + bstrDescription = + unmanaged.bstrDescription != 0 + ? Marshal.PtrToStringBSTR(unmanaged.bstrDescription) + : "", + bstrHelpFile = + unmanaged.bstrHelpFile != 0 ? Marshal.PtrToStringBSTR(unmanaged.bstrHelpFile) : "", + bstrSource = + unmanaged.bstrSource != 0 ? Marshal.PtrToStringBSTR(unmanaged.bstrSource) : "", + dwHelpContext = unmanaged.dwHelpContext, + pfnDeferredFillIn = unmanaged.pfnDeferredFillIn, + pvReserved = unmanaged.pvReserved, + scode = unmanaged.scode, + wCode = unmanaged.wCode, + wReserved = unmanaged.wReserved, + }; + } + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/ExcepInfoNative.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/ExcepInfoNative.cs new file mode 100644 index 00000000..aae929b1 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/ExcepInfoNative.cs @@ -0,0 +1,18 @@ +using System.Runtime.InteropServices; + +namespace ExcelDna.COMWrappers.NativeAOT.ComInterfaces +{ + [StructLayout(LayoutKind.Sequential)] + internal struct ExcepInfoNative + { + public short wCode; + public short wReserved; + public nint bstrSource; + public nint bstrDescription; + public nint bstrHelpFile; + public int dwHelpContext; + public nint pvReserved; + public nint pfnDeferredFillIn; + public int scode; + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/IDispatch.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/IDispatch.cs new file mode 100644 index 00000000..371c14cf --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/IDispatch.cs @@ -0,0 +1,38 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; +using System.Runtime.InteropServices.Marshalling; + +namespace ExcelDna.COMWrappers.NativeAOT.ComInterfaces +{ + [GeneratedComInterface] + [Guid("00020400-0000-0000-C000-000000000046")] + internal partial interface IDispatch + { + [PreserveSig] + int GetTypeInfoCount(out uint pctinfo); + + [PreserveSig] + int GetTypeInfo(uint iTInfo, uint lcid, out nint ppTInfo); + + [PreserveSig] + int GetIDsOfNames( + ref Guid riid, + [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] rgszNames, + uint cNames, + uint lcid, + [MarshalAs(UnmanagedType.LPArray)] int[] rgDispId + ); + + [PreserveSig] + int Invoke( + int dispIdMember, + Guid riid, + uint lcid, + INVOKEKIND wFlags, + [MarshalUsing(typeof(DispParamsMarshaller))] ref DispParams pDispParams, + [MarshalUsing(typeof(VariantMarshaller))] ref Variant pVarResult, + [MarshalUsing(typeof(ExcepInfoMarshaller))] ref ExcepInfo pExcepInfo, + ref uint puArgErr + ); + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/UnknownObject.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/UnknownObject.cs new file mode 100644 index 00000000..10e3294d --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/UnknownObject.cs @@ -0,0 +1,20 @@ +using System.Runtime.InteropServices.Marshalling; + +namespace ExcelDna.COMWrappers.NativeAOT.ComInterfaces +{ + internal class UnknownObject + { + public IntPtr P { get; } + + public UnknownObject(IntPtr unknown) + { + P = unknown; + } + + public unsafe bool HasInterface(ref Guid guid) + { + StrategyBasedComWrappers.DefaultIUnknownStrategy.QueryInterface(P.ToPointer(), in guid, out void* ppObj); + return ppObj != null; + } + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/Variant.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/Variant.cs new file mode 100644 index 00000000..22ba9209 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/Variant.cs @@ -0,0 +1,12 @@ +namespace ExcelDna.COMWrappers.NativeAOT.ComInterfaces +{ + internal struct Variant + { + public Variant(object? value) + { + Value = value; + } + + public object? Value { get; set; } + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/VariantBoolNative.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/VariantBoolNative.cs new file mode 100644 index 00000000..61121ecd --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/VariantBoolNative.cs @@ -0,0 +1,8 @@ +namespace ExcelDna.COMWrappers.NativeAOT.ComInterfaces +{ + internal enum VariantBoolNative : short + { + VARIANT_FALSE = 0, + VARIANT_TRUE = -1 + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/VariantMarshaller.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/VariantMarshaller.cs new file mode 100644 index 00000000..c4e1a521 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/VariantMarshaller.cs @@ -0,0 +1,77 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace ExcelDna.COMWrappers.NativeAOT.ComInterfaces +{ + [CustomMarshaller(typeof(Variant), MarshalMode.Default, typeof(VariantMarshaller))] + internal static class VariantMarshaller + { + public const int DISP_E_PARAMNOTFOUND = -2147352572; + + public static VariantNative ConvertToUnmanaged(Variant managed) + { + if (managed.Value == Type.Missing) + { + return new VariantNative + { + vt = (ushort)VariantTypeNative.VT_ERROR, + scode = DISP_E_PARAMNOTFOUND, + }; + } + + if (managed.Value != null && managed.Value.GetType().IsEnum) + { + return new VariantNative { vt = (ushort)VariantTypeNative.VT_I4, lVal = (int)managed.Value }; + } + + return managed.Value switch + { + bool boolVal + => new VariantNative + { + vt = (ushort)VariantTypeNative.VT_BOOL, + boolVal = (short)( + boolVal ? VariantBoolNative.VARIANT_TRUE : VariantBoolNative.VARIANT_FALSE + ), + }, + int lVal => new VariantNative { vt = (ushort)VariantTypeNative.VT_I4, lVal = lVal, }, + string bstrVal + => new VariantNative + { + vt = (ushort)VariantTypeNative.VT_BSTR, + bstrVal = Marshal.StringToBSTR(bstrVal), + }, + null => new VariantNative { vt = (ushort)VariantTypeNative.VT_NULL, }, + _ => + throw new NotImplementedException(managed.Value.GetType().ToString()) + , + }; + } + + public static unsafe Variant ConvertToManaged(VariantNative unmanaged) + { + if ((VariantTypeNative)unmanaged.vt == VariantTypeNative.VT_ERROR && unmanaged.scode == DISP_E_PARAMNOTFOUND) + return new Variant(Type.Missing); + + return (VariantTypeNative)unmanaged.vt switch + { + VariantTypeNative.VT_BOOL + => new Variant + { + Value = unmanaged.boolVal == (short)VariantBoolNative.VARIANT_TRUE, + }, + VariantTypeNative.VT_I4 => new Variant { Value = unmanaged.lVal, }, + VariantTypeNative.VT_BSTR + => new Variant { Value = Marshal.PtrToStringBSTR(unmanaged.bstrVal), }, + VariantTypeNative.VT_DISPATCH + => new Variant + { + Value = new DispatchObject(unmanaged.pdispVal) + }, + VariantTypeNative.VT_EMPTY => new Variant { }, + VariantTypeNative.VT_NULL => new Variant { }, + _ => throw new NotImplementedException(unmanaged.vt.ToString()), + }; + } + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/VariantNative.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/VariantNative.cs new file mode 100644 index 00000000..04c92157 --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/VariantNative.cs @@ -0,0 +1,209 @@ +using System.Runtime.InteropServices; + +namespace ExcelDna.COMWrappers.NativeAOT.ComInterfaces +{ + [StructLayout(LayoutKind.Explicit)] + internal struct VariantNative + { + [FieldOffset(0)] + public DECIMAL decVal; + + [FieldOffset(0)] + public ushort vt; + + [FieldOffset(2)] + public ushort wReserved1; + + [FieldOffset(4)] + public ushort wReserved2; + + [FieldOffset(6)] + public ushort wReserved3; + + [FieldOffset(8)] + public long llVal; + + [FieldOffset(8)] + public int lVal; + + [FieldOffset(8)] + public byte bVal; + + [FieldOffset(8)] + public short iVal; + + [FieldOffset(8)] + public float fltVal; + + [FieldOffset(8)] + public double dblVal; + + [FieldOffset(8)] + public short boolVal; + + [FieldOffset(8)] + public short __OBSOLETE__VARIANT_BOOL; + + [FieldOffset(8)] + public int scode; + + [FieldOffset(8)] + public CY cyVal; + + [FieldOffset(8)] + public double date; + + [FieldOffset(8)] + public nint bstrVal; + + [FieldOffset(8)] + public nint punkVal; + + [FieldOffset(8)] + public nint pdispVal; + + [FieldOffset(8)] + public nint parray; + + [FieldOffset(8)] + public nint pbVal; + + [FieldOffset(8)] + public nint piVal; + + [FieldOffset(8)] + public nint plVal; + + [FieldOffset(8)] + public nint pllVal; + + [FieldOffset(8)] + public nint pfltVal; + + [FieldOffset(8)] + public nint pdblVal; + + [FieldOffset(8)] + public nint pboolVal; + + [FieldOffset(8)] + public nint __OBSOLETE__VARIANT_PBOOL; + + [FieldOffset(8)] + public nint pscode; + + [FieldOffset(8)] + public nint pcyVal; + + [FieldOffset(8)] + public nint pdate; + + [FieldOffset(8)] + public nint pbstrVal; + + [FieldOffset(8)] + public nint ppunkVal; + + [FieldOffset(8)] + public nint ppdispVal; + + [FieldOffset(8)] + public nint pparray; + + [FieldOffset(8)] + public nint pvarVal; + + [FieldOffset(8)] + public nint byref; + + [FieldOffset(8)] + public sbyte cVal; + + [FieldOffset(8)] + public ushort uiVal; + + [FieldOffset(8)] + public uint ulVal; + + [FieldOffset(8)] + public ulong ullVal; + + [FieldOffset(8)] + public int intVal; + + [FieldOffset(8)] + public uint uintVal; + + [FieldOffset(8)] + public nint pdecVal; + + [FieldOffset(8)] + public nint pcVal; + + [FieldOffset(8)] + public nint puiVal; + + [FieldOffset(8)] + public nint pulVal; + + [FieldOffset(8)] + public nint pullVal; + + [FieldOffset(8)] + public nint pintVal; + + [FieldOffset(8)] + public nint puintVal; + + [FieldOffset(8)] + public TagBRECORD __tagBRECORD; + + [StructLayout(LayoutKind.Explicit)] + internal struct CY + { + [FieldOffset(0)] + public uint Lo; + + [FieldOffset(4)] + public int Hi; + + [FieldOffset(0)] + public long int64; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct TagBRECORD + { + public nint pvRecord; + public nint pRecInfo; + } + + [StructLayout(LayoutKind.Explicit)] + internal struct DECIMAL + { + [FieldOffset(0)] + public ushort wReserved; + + [FieldOffset(2)] + public ushort signscale; + + [FieldOffset(2)] + public byte scale; + + [FieldOffset(3)] + public byte sign; + + [FieldOffset(4)] + public uint Hi32; + + [FieldOffset(8)] + public ulong Lo64; + + [FieldOffset(8)] + public uint Lo32; + + [FieldOffset(12)] + public uint Mid32; + } + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/VariantTypeNative.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/VariantTypeNative.cs new file mode 100644 index 00000000..9e204f1c --- /dev/null +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/VariantTypeNative.cs @@ -0,0 +1,58 @@ +namespace ExcelDna.COMWrappers.NativeAOT.ComInterfaces +{ + internal enum VariantTypeNative : ushort + { + VT_EMPTY = 0, + VT_NULL = 1, + VT_I2 = 2, + VT_I4 = 3, + VT_R4 = 4, + VT_R8 = 5, + VT_CY = 6, + VT_DATE = 7, + VT_BSTR = 8, + VT_DISPATCH = 9, + VT_ERROR = 10, + VT_BOOL = 11, + VT_VARIANT = 12, + VT_UNKNOWN = 13, + VT_DECIMAL = 14, + VT_I1 = 16, + VT_UI1 = 17, + VT_UI2 = 18, + VT_UI4 = 19, + VT_I8 = 20, + VT_UI8 = 21, + VT_INT = 22, + VT_UINT = 23, + VT_VOID = 24, + VT_HRESULT = 25, + VT_PTR = 26, + VT_SAFEARRAY = 27, + VT_CARRAY = 28, + VT_USERDEFINED = 29, + VT_LPSTR = 30, + VT_LPWSTR = 31, + VT_RECORD = 36, + VT_INT_PTR = 37, + VT_UINT_PTR = 38, + VT_FILETIME = 64, + VT_BLOB = 65, + VT_STREAM = 66, + VT_STORAGE = 67, + VT_STREAMED_OBJECT = 68, + VT_STORED_OBJECT = 69, + VT_BLOB_OBJECT = 70, + VT_CF = 71, + VT_CLSID = 72, + VT_VERSIONED_STREAM = 73, + VT_BSTR_BLOB = 0xfff, + VT_VECTOR = 0x1000, + VT_ARRAY = 0x2000, + VT_BYREF = 0x4000, + VT_RESERVED = 0x8000, + VT_X = 0xffff, + VT_Y = 0xfff, + VT_TYPEMASK = 0xfff + } +} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs b/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs index 896ce5e7..3521d769 100644 --- a/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs +++ b/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs @@ -1,4 +1,5 @@ using ExcelDna.ComInterop; +using ExcelDna.COMWrappers.NativeAOT.ComInterfaces; namespace ExcelDna.COMWrappers.NativeAOT { @@ -6,32 +7,32 @@ public class TypeAdapter : IType { public object GetProperty(string name, object comObject) { - return (comObject as ComObject)!.GetProperty(name)!; + return (comObject as DispatchObject)!.GetProperty(name)!; } public object GetIndex(int i, object comObject) { - return (comObject as ComObject)!.GetIndex(i)!; + return (comObject as DispatchObject)!.GetIndex(i)!; } public bool Is(ref Guid guid, object comObject) { - return (comObject as ComObject)!.HasInterface(ref guid); + return (comObject as DispatchObject)!.HasInterface(ref guid); } public object Invoke(string name, object[] args, object comObject) { - return (comObject as ComObject)!.Invoke(name, args)!; + return (comObject as DispatchObject)!.Invoke(name, args)!; } public void SetProperty(string name, object value, object comObject) { - (comObject as ComObject)!.SetProperty(name, value); + (comObject as DispatchObject)!.SetProperty(name, value); } public object GetObject(IntPtr pUnk) { - return new ComObject(pUnk); + return new DispatchObject(pUnk); } public void ReleaseObject(object comObject) @@ -40,7 +41,7 @@ public void ReleaseObject(object comObject) public bool HasProperty(string name, object comObject) { - return (comObject as ComObject)!.HasProperty(name); + return (comObject as DispatchObject)!.HasProperty(name); } } } diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/DispParams.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/DispParams.cs deleted file mode 100644 index 19fd236c..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/DispParams.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Addin.Types.Managed; - -public struct DispParams -{ - public int cArgs; - public int cNamedArgs; - public int rgdispidNamedArgs; - public Variant[] rgvarg; -} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/ExcepInfo.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/ExcepInfo.cs deleted file mode 100644 index 77f3e822..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/ExcepInfo.cs +++ /dev/null @@ -1,53 +0,0 @@ -namespace Addin.Types.Managed; - -public struct ExcepInfo -{ - // - // Summary: - // Describes the error intended for the customer. - public string bstrDescription; - - // - // Summary: - // Contains the fully-qualified drive, path, and file name of a Help file that contains - // more information about the error. - public string bstrHelpFile; - - // - // Summary: - // Indicates the name of the source of the exception. Typically, this is an application - // name. - public string bstrSource; - - // - // Summary: - // Indicates the Help context ID of the topic within the Help file. - public int dwHelpContext; - - // - // Summary: - // Represents a pointer to a function that takes an System.Runtime.InteropServices.EXCEPINFO - // structure as an argument and returns an HRESULT value. If deferred fill-in is - // not desired, this field is set to null. - public nint pfnDeferredFillIn; - - // - // Summary: - // This field is reserved; it must be set to null. - public nint pvReserved; - - // - // Summary: - // A return value describing the error. - public int scode; - - // - // Summary: - // Represents an error code identifying the error. - public short wCode; - - // - // Summary: - // This field is reserved; it must be set to 0. - public short wReserved; -} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/Variant.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/Variant.cs deleted file mode 100644 index ec2ac194..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/Variant.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Addin.Types.Managed; - -public struct Variant -{ - public Variant(object? value) - { - Value = value; - } - - public object? Value { get; set; } - public IntPtr DispVal { get; set; } -} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/XlOper.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/XlOper.cs deleted file mode 100644 index 8ce227d9..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Managed/XlOper.cs +++ /dev/null @@ -1,60 +0,0 @@ -namespace Addin.Types.Managed; - -using Addin.Types.Unmanaged; -using System.Runtime.InteropServices; -using static Addin.Types.Unmanaged.ExcelConstants; - -public class XlOper -{ - xloper12 _instance; - - public XlOper() - { - _instance = new(); - } - - public XlOper(string str) - { - // Calculate sizes - var strLen = str.Length + 1; - var charLen = Marshal.SizeOf(str[0]); - var byteCount = charLen * strLen; - - // Create byte array, with the length stored in the first char and the string contents on the rest - var bytes = new char[strLen]; - bytes[0] = (char)(strLen - 1); - Buffer.BlockCopy(str.ToCharArray(), 0, bytes, charLen, byteCount - charLen); - - // Convert to unmanaged bytes - var strPtr = Marshal.AllocHGlobal(byteCount); - Marshal.Copy(bytes, 0, strPtr, strLen); - - // Add to XlOper structure - xloper12 lpx = new() { xltype = xltypeStr }; - lpx.val.str = strPtr; - _instance = lpx; - } - - public XlOper(nint ptr) - { - _instance = Marshal.PtrToStructure(ptr); - } - - public override string? ToString() - { - if (_instance.xltype != xltypeStr) - throw new NotSupportedException(); - var str = Marshal.PtrToStringUni(_instance.val.str); - var bytes = str?.ToCharArray().Skip(1).ToArray(); - return new string(bytes); - } - - public nint ToPtr() - { - var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(_instance)); - - Marshal.StructureToPtr(_instance, ptr, false); - - return ptr; - } -} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Array.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Array.cs deleted file mode 100644 index ccd50a4a..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Array.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Addin.Types.Marshalling; - -public static class Array -{ - public static nint ArrayToPtr(T[] str) - { - var size = Marshal.SizeOf(); - var len = str.Length; - var ptrs = new nint[str.Length]; - var basePtr = Marshal.AllocHGlobal(size * len); - for (int i = 0; i < len; ++i) - { - ptrs[i] = nint.Add(basePtr, i * size); - Marshal.StructureToPtr(str[i], ptrs[i], false); - } - return basePtr; - } - - public static T[] PtrToArray(nint str, int len) - { - var size = Marshal.SizeOf(); - var ret = new T[len]; - for (int i = 0; i < len; ++i) - { - ret[i] = Marshal.PtrToStructure(nint.Add(str, i * size)); - } - return ret; - } -} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/DispParams.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/DispParams.cs deleted file mode 100644 index 390b3a1d..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/DispParams.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Runtime.InteropServices.Marshalling; - -namespace Addin.Types.Marshalling; - -[CustomMarshaller(typeof(Managed.DispParams), MarshalMode.Default, typeof(DispParams))] -public static class DispParams -{ - public static unsafe Unmanaged.DispParams ConvertToUnmanaged(Managed.DispParams managed) - { - return new Unmanaged.DispParams - { - cArgs = managed.cArgs, - cNamedArgs = managed.cNamedArgs, - rgdispidNamedArgs = &managed.rgdispidNamedArgs, - rgvarg = - managed.rgvarg != null - ? Array.ArrayToPtr(managed.rgvarg.Reverse().Select(Variant.ConvertToUnmanaged).ToArray()) - : nint.Zero - }; - } - - public static unsafe Managed.DispParams ConvertToManaged(Unmanaged.DispParams unmanaged) - { - return new Managed.DispParams - { - cArgs = unmanaged.cArgs, - cNamedArgs = unmanaged.cNamedArgs, - rgdispidNamedArgs = *unmanaged.rgdispidNamedArgs, - rgvarg = Array - .PtrToArray(unmanaged.rgvarg, unmanaged.cArgs) - .Select(Variant.ConvertToManaged) - .Reverse() - .ToArray(), - }; - } -} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/ExcepInfo.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/ExcepInfo.cs deleted file mode 100644 index 5eebbe1b..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/ExcepInfo.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -namespace Addin.Types.Marshalling; - -[CustomMarshaller(typeof(Managed.ExcepInfo), MarshalMode.Default, typeof(ExcepInfo))] -public static class ExcepInfo -{ - public static Unmanaged.ExcepInfo ConvertToUnmanaged(Managed.ExcepInfo managed) - { - return new Unmanaged.ExcepInfo - { - bstrDescription = Marshal.StringToBSTR(managed.bstrDescription), - bstrHelpFile = Marshal.StringToBSTR(managed.bstrHelpFile), - bstrSource = Marshal.StringToBSTR(managed.bstrSource), - dwHelpContext = managed.dwHelpContext, - pfnDeferredFillIn = managed.pfnDeferredFillIn, - pvReserved = managed.pvReserved, - scode = managed.scode, - wCode = managed.wCode, - wReserved = managed.wReserved, - }; - } - - public static Managed.ExcepInfo ConvertToManaged(Unmanaged.ExcepInfo unmanaged) - { - return new Managed.ExcepInfo - { - bstrDescription = - unmanaged.bstrDescription != 0 - ? Marshal.PtrToStringBSTR(unmanaged.bstrDescription) - : "", - bstrHelpFile = - unmanaged.bstrHelpFile != 0 ? Marshal.PtrToStringBSTR(unmanaged.bstrHelpFile) : "", - bstrSource = - unmanaged.bstrSource != 0 ? Marshal.PtrToStringBSTR(unmanaged.bstrSource) : "", - dwHelpContext = unmanaged.dwHelpContext, - pfnDeferredFillIn = unmanaged.pfnDeferredFillIn, - pvReserved = unmanaged.pvReserved, - scode = unmanaged.scode, - wCode = unmanaged.wCode, - wReserved = unmanaged.wReserved, - }; - } -} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Variant.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Variant.cs deleted file mode 100644 index d3225ef3..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Marshalling/Variant.cs +++ /dev/null @@ -1,76 +0,0 @@ -using Addin.ComApi; -using Addin.Types.Unmanaged; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -namespace Addin.Types.Marshalling; - -[CustomMarshaller(typeof(Managed.Variant), MarshalMode.Default, typeof(Variant))] -public static class Variant -{ - public const int DISP_E_PARAMNOTFOUND = -2147352572; - - public static Unmanaged.Variant ConvertToUnmanaged(Managed.Variant managed) - { - if (managed.Value == Type.Missing) - { - return new Unmanaged.Variant - { - vt = (ushort)VariantType.VT_ERROR, - scode = DISP_E_PARAMNOTFOUND, - }; - } - - return managed.Value switch - { - bool boolVal - => new Unmanaged.Variant - { - vt = (ushort)VariantType.VT_BOOL, - boolVal = (short)( - boolVal ? VariantBool.VARIANT_TRUE : VariantBool.VARIANT_FALSE - ), - }, - int lVal => new Unmanaged.Variant { vt = (ushort)VariantType.VT_I4, lVal = lVal, }, - string bstrVal - => new Unmanaged.Variant - { - vt = (ushort)VariantType.VT_BSTR, - bstrVal = Marshal.StringToBSTR(bstrVal), - }, - null => new Unmanaged.Variant { vt = (ushort)VariantType.VT_NULL, }, - _ => - throw new NotImplementedException(managed.Value.GetType().ToString()) - , - }; - } - - public static unsafe Managed.Variant ConvertToManaged(Unmanaged.Variant unmanaged) - { - if ((VariantType)unmanaged.vt == VariantType.VT_ERROR && unmanaged.scode == DISP_E_PARAMNOTFOUND) - return new Managed.Variant(Type.Missing); - - return (VariantType)unmanaged.vt switch - { - VariantType.VT_BOOL - => new Managed.Variant - { - Value = unmanaged.boolVal == (short)VariantBool.VARIANT_TRUE, - }, - VariantType.VT_I4 => new Managed.Variant { Value = unmanaged.lVal, }, - VariantType.VT_BSTR - => new Managed.Variant { Value = Marshal.PtrToStringBSTR(unmanaged.bstrVal), }, - VariantType.VT_DISPATCH - => new Managed.Variant - { - Value = ComInterfaceMarshaller.ConvertToManaged( - (void*)unmanaged.pdispVal - ), - DispVal = unmanaged.pdispVal - }, - VariantType.VT_EMPTY => new Managed.Variant { }, - VariantType.VT_NULL => new Managed.Variant { }, - _ => throw new NotImplementedException(unmanaged.vt.ToString()), - }; - } -} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ClsCtx.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ClsCtx.cs deleted file mode 100644 index ea4d45f6..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ClsCtx.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace Addin.Types.Unmanaged; - -public enum ClsCtx : uint -{ - CLSCTX_INPROC_SERVER = 0x1, - CLSCTX_INPROC_HANDLER = 0x2, - CLSCTX_LOCAL_SERVER = 0x4, - CLSCTX_INPROC_SERVER16 = 0x8, - CLSCTX_REMOTE_SERVER = 0x10, - CLSCTX_INPROC_HANDLER16 = 0x20, - CLSCTX_RESERVED1 = 0x40, - CLSCTX_RESERVED2 = 0x80, - CLSCTX_RESERVED3 = 0x100, - CLSCTX_RESERVED4 = 0x200, - CLSCTX_NO_CODE_DOWNLOAD = 0x400, - CLSCTX_RESERVED5 = 0x800, - CLSCTX_NO_CUSTOM_MARSHAL = 0x1000, - CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000, - CLSCTX_NO_FAILURE_LOG = 0x4000, - CLSCTX_DISABLE_AAA = 0x8000, - CLSCTX_ENABLE_AAA = 0x10000, - CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000, - CLSCTX_ACTIVATE_X86_SERVER = 0x40000, - CLSCTX_ACTIVATE_32_BIT_SERVER = CLSCTX_ACTIVATE_X86_SERVER, - CLSCTX_ACTIVATE_64_BIT_SERVER = 0x80000, - CLSCTX_ENABLE_CLOAKING = 0x100000, - CLSCTX_APPCONTAINER = 0x400000, - CLSCTX_ACTIVATE_AAA_AS_IU = 0x800000, - CLSCTX_RESERVED6 = 0x1000000, - CLSCTX_ACTIVATE_ARM32_SERVER = 0x2000000, - CLSCTX_ALLOW_LOWER_TRUST_REGISTRATION = 0x4000000, - CLSCTX_PS_DLL = 0x80000000 -}; diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ComConstants.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ComConstants.cs deleted file mode 100644 index 9c436bfe..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ComConstants.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Addin.Types.Unmanaged; - -public class ComConstants -{ - public const int LOCALE_SYSTEM_DEFAULT = 0x0800; - public const int LOCALE_USER_DEFAULT = 0x0400; - public const int DISPID_PROPERTYPUT = -3; - public const uint OBJID_NATIVEOM = 0xFFFFFFF0; -} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/DispParams.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/DispParams.cs deleted file mode 100644 index 17942587..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/DispParams.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Addin.Types.Unmanaged; - -[StructLayout(LayoutKind.Sequential)] -public unsafe struct DispParams -{ - public nint rgvarg; - public int* rgdispidNamedArgs; - public int cArgs; - public int cNamedArgs; -} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ExcelConstants.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ExcelConstants.cs deleted file mode 100644 index 1ca0336a..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ExcelConstants.cs +++ /dev/null @@ -1,100 +0,0 @@ -namespace Addin.Types.Unmanaged; - -public static class ExcelConstants -{ - // Function number bits - public static readonly int xlCommand = 0x8000; - public static readonly int xlSpecial = 0x4000; - public static readonly int xlIntl = 0x2000; - public static readonly int xlPrompt = 0x1000; - - // Auxiliary function numbers - // These functions are available only from the C API, - // not from the Excel macro language. - public static readonly int xlFree = 0 | xlSpecial; - public static readonly int xlStack = 1 | xlSpecial; - public static readonly int xlCoerce = 2 | xlSpecial; - public static readonly int xlSet = 3 | xlSpecial; - public static readonly int xlSheetId = 4 | xlSpecial; - public static readonly int xlSheetNm = 5 | xlSpecial; - public static readonly int xlAbort = 6 | xlSpecial; - - // Returns application's hinstance as an integer value, supported on 32-bit platform only - public static readonly int xlGetInst = 7 | xlSpecial; - public static readonly int xlGetHwnd = 8 | xlSpecial; - public static readonly int xlGetName = 9 | xlSpecial; - public static readonly int xlEnableXLMsgs = 10 | xlSpecial; - public static readonly int xlDisableXLMsgs = 11 | xlSpecial; - public static readonly int xlDefineBinaryName = 12 | xlSpecial; - public static readonly int xlGetBinaryName = 13 | xlSpecial; - - // GetFooInfo are valid only for calls to LPenHelper - public static readonly int xlGetFmlaInfo = 14 | xlSpecial; - public static readonly int xlGetMouseInfo = 15 | xlSpecial; - - // Set return value from an asynchronous function call - public static readonly int xlAsyncReturn = 16 | xlSpecial; - - // Register an XLL event - public static readonly int xlEventRegister = 17 | xlSpecial; - - // Returns true if running on Compute Cluster - public static readonly int xlRunningOnCluster = 18 | xlSpecial; - - // Returns application's hinstance as a handle, supported on both 32-bit and 64-bit platforms - public static readonly int xlGetInstPtr = 19 | xlSpecial; - - public static readonly int xlfRegister = 149; - - public static readonly int xltypeNum = 0x0001; - public static readonly int xltypeStr = 0x0002; - public static readonly int xltypeBool = 0x0004; - public static readonly int xltypeRef = 0x0008; - public static readonly int xltypeErr = 0x0010; - public static readonly int xltypeFlow = 0x0020; - public static readonly int xltypeMulti = 0x0040; - public static readonly int xltypeMissing = 0x0080; - public static readonly int xltypeNil = 0x0100; - public static readonly int xltypeSRef = 0x0400; - public static readonly int xltypeInt = 0x0800; - - public static readonly int xlbitXLFree = 0x1000; - public static readonly int xlbitDLLFree = 0x4000; - - public static readonly int xltypeBigData = xltypeStr | xltypeInt; - - // Error codes - // Used for val.err field of XLOPER and XLOPER12 structures - // when constructing error XLOPERs and XLOPER12s - public static readonly int xlerrNull = 0; - public static readonly int xlerrDiv0 = 7; - public static readonly int xlerrValue = 15; - public static readonly int xlerrRef = 23; - public static readonly int xlerrName = 29; - public static readonly int xlerrNum = 36; - public static readonly int xlerrNA = 42; - public static readonly int xlerrGettingData = 43; - - // Flow data types - // Used for val.flow.xlflow field of XLOPER and XLOPER12 structures - // when constructing flow-control XLOPERs and XLOPER12s - public static readonly int xlflowHalt = 1; - public static readonly int xlflowGoto = 2; - public static readonly int xlflowRestart = 8; - public static readonly int xlflowPause = 16; - public static readonly int xlflowResume = 64; - - // Return codes - // These values can be returned from Excel4(), Excel4v(), Excel12() or Excel12v(). - public static readonly int xlretSuccess = 0; // success - public static readonly int xlretAbort = 1; // macro halted - public static readonly int xlretInvXlfn = 2; // invalid function number - public static readonly int xlretInvCount = 4; // invalid number of arguments - public static readonly int xlretInvXloper = 8; // invalid OPER structure - public static readonly int xlretStackOvfl = 16; // stack overflow - public static readonly int xlretFailed = 32; // command failed - public static readonly int xlretUncalced = 64; // uncalced cell - public static readonly int xlretNotThreadSafe = 128; // not allowed during multi-threaded calc - public static readonly int xlretInvAsynchronousContext = 256; // invalid asynchronous function handle - public static readonly int xlretNotClusterSafe = 512; // not supported on cluster -} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ExcepInfo.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ExcepInfo.cs deleted file mode 100644 index efa48d96..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/ExcepInfo.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Addin.Types.Unmanaged; - -[StructLayout(LayoutKind.Sequential)] -public struct ExcepInfo -{ - public short wCode; - public short wReserved; - public nint bstrSource; - public nint bstrDescription; - public nint bstrHelpFile; - public int dwHelpContext; - public nint pvReserved; - public nint pfnDeferredFillIn; - public int scode; -} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/Variant.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/Variant.cs deleted file mode 100644 index c489c3f3..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/Variant.cs +++ /dev/null @@ -1,208 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Addin.Types.Unmanaged; - -[StructLayout(LayoutKind.Explicit)] -public struct Variant -{ - [FieldOffset(0)] - public DECIMAL decVal; - - [FieldOffset(0)] - public ushort vt; - - [FieldOffset(2)] - public ushort wReserved1; - - [FieldOffset(4)] - public ushort wReserved2; - - [FieldOffset(6)] - public ushort wReserved3; - - [FieldOffset(8)] - public long llVal; - - [FieldOffset(8)] - public int lVal; - - [FieldOffset(8)] - public byte bVal; - - [FieldOffset(8)] - public short iVal; - - [FieldOffset(8)] - public float fltVal; - - [FieldOffset(8)] - public double dblVal; - - [FieldOffset(8)] - public short boolVal; - - [FieldOffset(8)] - public short __OBSOLETE__VARIANT_BOOL; - - [FieldOffset(8)] - public int scode; - - [FieldOffset(8)] - public CY cyVal; - - [FieldOffset(8)] - public double date; - - [FieldOffset(8)] - public nint bstrVal; - - [FieldOffset(8)] - public nint punkVal; - - [FieldOffset(8)] - public nint pdispVal; - - [FieldOffset(8)] - public nint parray; - - [FieldOffset(8)] - public nint pbVal; - - [FieldOffset(8)] - public nint piVal; - - [FieldOffset(8)] - public nint plVal; - - [FieldOffset(8)] - public nint pllVal; - - [FieldOffset(8)] - public nint pfltVal; - - [FieldOffset(8)] - public nint pdblVal; - - [FieldOffset(8)] - public nint pboolVal; - - [FieldOffset(8)] - public nint __OBSOLETE__VARIANT_PBOOL; - - [FieldOffset(8)] - public nint pscode; - - [FieldOffset(8)] - public nint pcyVal; - - [FieldOffset(8)] - public nint pdate; - - [FieldOffset(8)] - public nint pbstrVal; - - [FieldOffset(8)] - public nint ppunkVal; - - [FieldOffset(8)] - public nint ppdispVal; - - [FieldOffset(8)] - public nint pparray; - - [FieldOffset(8)] - public nint pvarVal; - - [FieldOffset(8)] - public nint byref; - - [FieldOffset(8)] - public sbyte cVal; - - [FieldOffset(8)] - public ushort uiVal; - - [FieldOffset(8)] - public uint ulVal; - - [FieldOffset(8)] - public ulong ullVal; - - [FieldOffset(8)] - public int intVal; - - [FieldOffset(8)] - public uint uintVal; - - [FieldOffset(8)] - public nint pdecVal; - - [FieldOffset(8)] - public nint pcVal; - - [FieldOffset(8)] - public nint puiVal; - - [FieldOffset(8)] - public nint pulVal; - - [FieldOffset(8)] - public nint pullVal; - - [FieldOffset(8)] - public nint pintVal; - - [FieldOffset(8)] - public nint puintVal; - - [FieldOffset(8)] - public __tagBRECORD __tagBRECORD; -} - -[StructLayout(LayoutKind.Explicit)] -public struct CY -{ - [FieldOffset(0)] - public uint Lo; - - [FieldOffset(4)] - public int Hi; - - [FieldOffset(0)] - public long int64; -} - -[StructLayout(LayoutKind.Sequential)] -public struct __tagBRECORD -{ - public nint pvRecord; - public nint pRecInfo; -} - -[StructLayout(LayoutKind.Explicit)] -public struct DECIMAL -{ - [FieldOffset(0)] - public ushort wReserved; - - [FieldOffset(2)] - public ushort signscale; - - [FieldOffset(2)] - public byte scale; - - [FieldOffset(3)] - public byte sign; - - [FieldOffset(4)] - public uint Hi32; - - [FieldOffset(8)] - public ulong Lo64; - - [FieldOffset(8)] - public uint Lo32; - - [FieldOffset(12)] - public uint Mid32; -} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/VariantBool.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/VariantBool.cs deleted file mode 100644 index 1f4a2688..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/VariantBool.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Addin.Types.Unmanaged; - -public enum VariantBool : short -{ - VARIANT_FALSE = 0, - VARIANT_TRUE = -1 -} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/VariantType.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/VariantType.cs deleted file mode 100644 index 4fa206ac..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/VariantType.cs +++ /dev/null @@ -1,57 +0,0 @@ -namespace Addin.Types.Unmanaged; - -public enum VariantType : ushort -{ - VT_EMPTY = 0, - VT_NULL = 1, - VT_I2 = 2, - VT_I4 = 3, - VT_R4 = 4, - VT_R8 = 5, - VT_CY = 6, - VT_DATE = 7, - VT_BSTR = 8, - VT_DISPATCH = 9, - VT_ERROR = 10, - VT_BOOL = 11, - VT_VARIANT = 12, - VT_UNKNOWN = 13, - VT_DECIMAL = 14, - VT_I1 = 16, - VT_UI1 = 17, - VT_UI2 = 18, - VT_UI4 = 19, - VT_I8 = 20, - VT_UI8 = 21, - VT_INT = 22, - VT_UINT = 23, - VT_VOID = 24, - VT_HRESULT = 25, - VT_PTR = 26, - VT_SAFEARRAY = 27, - VT_CARRAY = 28, - VT_USERDEFINED = 29, - VT_LPSTR = 30, - VT_LPWSTR = 31, - VT_RECORD = 36, - VT_INT_PTR = 37, - VT_UINT_PTR = 38, - VT_FILETIME = 64, - VT_BLOB = 65, - VT_STREAM = 66, - VT_STORAGE = 67, - VT_STREAMED_OBJECT = 68, - VT_STORED_OBJECT = 69, - VT_BLOB_OBJECT = 70, - VT_CF = 71, - VT_CLSID = 72, - VT_VERSIONED_STREAM = 73, - VT_BSTR_BLOB = 0xfff, - VT_VECTOR = 0x1000, - VT_ARRAY = 0x2000, - VT_BYREF = 0x4000, - VT_RESERVED = 0x8000, - VT_X = 0xffff, - VT_Y = 0xfff, - VT_TYPEMASK = 0xfff -} diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/XlOper12.cs b/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/XlOper12.cs deleted file mode 100644 index 7edba2f8..00000000 --- a/Source/ExcelDna.COMWrappers.NativeAOT/Types/Unmanaged/XlOper12.cs +++ /dev/null @@ -1,178 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Addin.Types.Unmanaged; - -[StructLayout(LayoutKind.Sequential)] -public struct xlref12 -{ - /// RW->INT32->int - public int rwFirst; - - /// RW->INT32->int - public int rwLast; - - /// COL->INT32->int - public int colFirst; - - /// COL->INT32->int - public int colLast; -} - -[StructLayout(LayoutKind.Sequential)] -public struct xmlref12 -{ - /// WORD->short - public short count; - - /// XLREF12[1] - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1, ArraySubType = UnmanagedType.Struct)] - public xlref12[] reftbl; -} - -[StructLayout(LayoutKind.Sequential)] -public struct FP12 -{ - /// INT32->int - public int rows; - - /// INT32->int - public int columns; - - /// double[1] - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1, ArraySubType = UnmanagedType.R8)] - public double[] array; -} - -[StructLayout(LayoutKind.Sequential)] -public struct sref -{ - /// WORD->short - public short count; - - /// XLREF12->xlref12 - public xlref12 @ref; -} - -[StructLayout(LayoutKind.Sequential)] -public struct mref -{ - /// XLMREF12* - public nint lpmref; - - /// IDSHEET->DWORD_PTR->ULONG_PTR->int - public int idSheet; -} - -[StructLayout(LayoutKind.Sequential)] -public struct array -{ - /// xloper12* - public nint lparray; - - /// RW->INT32->int - public int rows; - - /// COL->INT32->int - public int columns; -} - -[StructLayout(LayoutKind.Explicit)] -public struct valflow -{ - /// int - [FieldOffset(0)] - public int level; - - /// int - [FieldOffset(0)] - public int tbctrl; - - /// IDSHEET->DWORD_PTR->ULONG_PTR->int - [FieldOffset(0)] - public int idSheet; -} - -[StructLayout(LayoutKind.Sequential)] -public struct flow -{ - public valflow valflow; - - /// RW->INT32->int - public int rw; - - /// COL->INT32->int - public int col; - - /// BYTE->char - public byte xlflow; -} - -[StructLayout(LayoutKind.Explicit)] -public struct h -{ - /// BYTE* - [FieldOffset(0)] - public nint lpbData; - - /// HANDLE->void* - [FieldOffset(0)] - public nint hdata; -} - -[StructLayout(LayoutKind.Sequential)] -public struct bigdata -{ - public h h; - - /// int - public int cbData; -} - -[StructLayout(LayoutKind.Explicit)] -public struct val -{ - /// double - [FieldOffset(0)] - public double num; - - /// XCHAR* - [FieldOffset(0)] - public nint str; - - /// BOOL->INT32->int - [FieldOffset(0)] - [MarshalAs(UnmanagedType.I1)] - public bool xbool; - - /// int - [FieldOffset(0)] - public int err; - - /// int - [FieldOffset(0)] - public int w; - - [FieldOffset(0)] - public sref sref; - - [FieldOffset(0)] - public mref mref; - - [FieldOffset(0)] - public array array; - - [FieldOffset(0)] - public flow flow; - - [FieldOffset(0)] - public bigdata bigdata; -} - -[StructLayout(LayoutKind.Sequential)] -public struct xloper12 -{ - public val val; - - /// DWORD->int - public int xltype; -} From f29ab0ede1c7fdbbade606e36086f0ba282cc25c Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sat, 22 Mar 2025 16:00:05 +0500 Subject: [PATCH 31/60] Cleaned ExcelDna.ComInterop files. --- .../TypeAdapter.cs | 4 +- .../{ => ComInterop}/ComInterop.cs | 110 ++++-------------- .../{ => ComInterop}/ComRegistration.cs | 0 .../{ => ComInterop}/ComServer.cs | 0 .../ExcelDna.Integration/ComInterop/IType.cs | 17 +++ .../ComInterop/TypeAdapter.cs | 54 +++++++++ .../ExcelDna.Integration/ComInterop/Util.cs | 15 +++ 7 files changed, 108 insertions(+), 92 deletions(-) rename Source/ExcelDna.Integration/{ => ComInterop}/ComInterop.cs (89%) rename Source/ExcelDna.Integration/{ => ComInterop}/ComRegistration.cs (100%) rename Source/ExcelDna.Integration/{ => ComInterop}/ComServer.cs (100%) create mode 100644 Source/ExcelDna.Integration/ComInterop/IType.cs create mode 100644 Source/ExcelDna.Integration/ComInterop/TypeAdapter.cs create mode 100644 Source/ExcelDna.Integration/ComInterop/Util.cs diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs b/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs index 3521d769..58789787 100644 --- a/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs +++ b/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs @@ -1,5 +1,5 @@ -using ExcelDna.ComInterop; -using ExcelDna.COMWrappers.NativeAOT.ComInterfaces; +using ExcelDna.COMWrappers.NativeAOT.ComInterfaces; +using ExcelDna.Integration.ComInterop; namespace ExcelDna.COMWrappers.NativeAOT { diff --git a/Source/ExcelDna.Integration/ComInterop.cs b/Source/ExcelDna.Integration/ComInterop/ComInterop.cs similarity index 89% rename from Source/ExcelDna.Integration/ComInterop.cs rename to Source/ExcelDna.Integration/ComInterop/ComInterop.cs index 8deef734..6d7ba34f 100644 --- a/Source/ExcelDna.Integration/ComInterop.cs +++ b/Source/ExcelDna.Integration/ComInterop/ComInterop.cs @@ -7,14 +7,13 @@ using ExcelDna.ComInterop; using HRESULT = System.Int32; -using IID = System.Guid; -using CLSID = System.Guid; -using DWORD = System.Int32; +using IID = System.Guid; +using CLSID = System.Guid; +using DWORD = System.Int32; using System.Runtime.CompilerServices; using System.Reflection; using System.Collections; using System.Threading; -using ExcelDna.Integration; namespace ExcelDna.ComInterop { @@ -174,11 +173,11 @@ internal interface ICustomTaskPaneConsumer public interface IRibbonControl { [DispId(1)] - string Id { [return: MarshalAs(UnmanagedType.BStr)][DispId(1)] get; } + string Id { [return: MarshalAs(UnmanagedType.BStr)] [DispId(1)] get; } [DispId(2)] - object Context { [return: MarshalAs(UnmanagedType.IDispatch)][DispId(2)] get; } + object Context { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(2)] get; } [DispId(3)] - string Tag { [return: MarshalAs(UnmanagedType.BStr)][DispId(3)] get; } + string Tag { [return: MarshalAs(UnmanagedType.BStr)] [DispId(3)] get; } } [ComImport] @@ -192,14 +191,14 @@ public interface IRibbonUI [DispId(2)] void InvalidateControl([In, MarshalAs(UnmanagedType.BStr)] string ControlID); [DispId(3)] - void InvalidateControlMso([MarshalAs(UnmanagedType.BStr)][In] string ControlID); + void InvalidateControlMso([MarshalAs(UnmanagedType.BStr)] [In] string ControlID); // The ActiveTab methods were added in Office 2010 [DispId(4)] - void ActivateTab([MarshalAs(UnmanagedType.BStr)][In] string ControlID); + void ActivateTab([MarshalAs(UnmanagedType.BStr)] [In] string ControlID); [DispId(5)] - void ActivateTabMso([MarshalAs(UnmanagedType.BStr)][In] string ControlID); + void ActivateTabMso([MarshalAs(UnmanagedType.BStr)] [In] string ControlID); [DispId(6)] - void ActivateTabQ([MarshalAs(UnmanagedType.BStr)][In] string ControlID, [MarshalAs(UnmanagedType.BStr)][In] string Namespace); + void ActivateTabQ([MarshalAs(UnmanagedType.BStr)] [In] string ControlID, [MarshalAs(UnmanagedType.BStr)] [In] string Namespace); } //// Actually from System.Windows.Forms.UnsafeNativeMethods @@ -249,23 +248,23 @@ public enum MsoCTPDockPositionRestrict public interface ICustomTaskPane { [DispId(0)] - string Title { [return: MarshalAs(UnmanagedType.BStr)][MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0)] get; } + string Title { [return: MarshalAs(UnmanagedType.BStr)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0)] get; } [DispId(1)] - object Application { [return: MarshalAs(UnmanagedType.IDispatch)][MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(1)] get; } + object Application { [return: MarshalAs(UnmanagedType.IDispatch)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(1)] get; } [DispId(2)] - object Window { [return: MarshalAs(UnmanagedType.IDispatch)][MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(2)] get; } + object Window { [return: MarshalAs(UnmanagedType.IDispatch)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(2)] get; } [DispId(3)] - bool Visible { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(3)] get; [param: In][MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(3)] set; } + bool Visible { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(3)] get; [param: In] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(3)] set; } [DispId(4)] - object ContentControl { [return: MarshalAs(UnmanagedType.IDispatch)][MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(4)] get; } + object ContentControl { [return: MarshalAs(UnmanagedType.IDispatch)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(4)] get; } [DispId(5)] - int Height { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(5)] get; [param: In][MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(5)] set; } + int Height { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(5)] get; [param: In] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(5)] set; } [DispId(6)] - int Width { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(6)] get; [param: In][MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(6)] set; } + int Width { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(6)] get; [param: In] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(6)] set; } [DispId(7)] - MsoCTPDockPosition DockPosition { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(7)] get; [param: In][MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(7)] set; } + MsoCTPDockPosition DockPosition { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(7)] get; [param: In] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(7)] set; } [DispId(8)] - MsoCTPDockPositionRestrict DockPositionRestrict { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(8)] get; [param: In][MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(8)] set; } + MsoCTPDockPositionRestrict DockPositionRestrict { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(8)] get; [param: In] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(8)] set; } [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(9)] void Delete(); } @@ -597,7 +596,7 @@ public interface IRtdServer [DispId(12)] [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] Array RefreshData(ref int topicCount); - + // // Summary: // Notifies a real-time data (RTD) server application that a topic is no longer @@ -848,72 +847,3 @@ out UInt32 pArgErr } #endregion - -namespace ExcelDna.ComInterop -{ - public interface IType - { - object GetObject(IntPtr pUnk); - void ReleaseObject(object comObject); - - bool HasProperty(string name, object comObject); - object GetProperty(string name, object comObject); - void SetProperty(string name, object value, object comObject); - object GetIndex(int i, object comObject); - object Invoke(string name, object[] args, object comObject); - bool Is(ref Guid guid, object comObject); - } - - internal static class Util - { - public static IType TypeAdapter - { get; } = NativeAOT.IsActive ? NativeAOT.TypeAdapter : new TypeAdapter(); - } - - internal class TypeAdapter : IType - { - public object GetProperty(string name, object comObject) - { - return comObject.GetType().InvokeMember(name, BindingFlags.GetProperty, null, comObject, null); - } - - public object GetIndex(int i, object comObject) - { - return comObject.GetType().InvokeMember("", BindingFlags.GetProperty, null, comObject, new object[] { i }); - } - - public bool Is(ref CLSID guid, object comObject) - { - IntPtr pUnk = Marshal.GetIUnknownForObject(comObject); - - IntPtr pButton; - Marshal.QueryInterface(pUnk, ref guid, out pButton); - return (pButton != IntPtr.Zero); - } - - public object Invoke(string name, object[] args, object comObject) - { - return comObject.GetType().InvokeMember(name, BindingFlags.InvokeMethod, null, comObject, args); - } - - public void SetProperty(string name, object value, object comObject) - { - comObject.GetType().InvokeMember(name, BindingFlags.SetProperty, null, comObject, new object[] { value }); - } - - public object GetObject(IntPtr pUnk) - { - return Marshal.GetObjectForIUnknown(pUnk); - } - - public void ReleaseObject(object comObject) - { - Marshal.ReleaseComObject(comObject); - } - - public bool HasProperty(string name, object comObject) - { - return ComInterop.DispatchHelper.HasProperty(comObject, name); - } - } -} diff --git a/Source/ExcelDna.Integration/ComRegistration.cs b/Source/ExcelDna.Integration/ComInterop/ComRegistration.cs similarity index 100% rename from Source/ExcelDna.Integration/ComRegistration.cs rename to Source/ExcelDna.Integration/ComInterop/ComRegistration.cs diff --git a/Source/ExcelDna.Integration/ComServer.cs b/Source/ExcelDna.Integration/ComInterop/ComServer.cs similarity index 100% rename from Source/ExcelDna.Integration/ComServer.cs rename to Source/ExcelDna.Integration/ComInterop/ComServer.cs diff --git a/Source/ExcelDna.Integration/ComInterop/IType.cs b/Source/ExcelDna.Integration/ComInterop/IType.cs new file mode 100644 index 00000000..c31b7124 --- /dev/null +++ b/Source/ExcelDna.Integration/ComInterop/IType.cs @@ -0,0 +1,17 @@ +using System; + +namespace ExcelDna.Integration.ComInterop +{ + public interface IType + { + object GetObject(IntPtr pUnk); + void ReleaseObject(object comObject); + + bool HasProperty(string name, object comObject); + object GetProperty(string name, object comObject); + void SetProperty(string name, object value, object comObject); + object GetIndex(int i, object comObject); + object Invoke(string name, object[] args, object comObject); + bool Is(ref Guid guid, object comObject); + } +} diff --git a/Source/ExcelDna.Integration/ComInterop/TypeAdapter.cs b/Source/ExcelDna.Integration/ComInterop/TypeAdapter.cs new file mode 100644 index 00000000..21e03252 --- /dev/null +++ b/Source/ExcelDna.Integration/ComInterop/TypeAdapter.cs @@ -0,0 +1,54 @@ +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using CLSID = System.Guid; + +namespace ExcelDna.Integration.ComInterop +{ + internal class TypeAdapter : IType + { + public object GetProperty(string name, object comObject) + { + return comObject.GetType().InvokeMember(name, BindingFlags.GetProperty, null, comObject, null); + } + + public object GetIndex(int i, object comObject) + { + return comObject.GetType().InvokeMember("", BindingFlags.GetProperty, null, comObject, new object[] { i }); + } + + public bool Is(ref CLSID guid, object comObject) + { + IntPtr pUnk = Marshal.GetIUnknownForObject(comObject); + + IntPtr pObj; + Marshal.QueryInterface(pUnk, ref guid, out pObj); + return (pObj != IntPtr.Zero); + } + + public object Invoke(string name, object[] args, object comObject) + { + return comObject.GetType().InvokeMember(name, BindingFlags.InvokeMethod, null, comObject, args); + } + + public void SetProperty(string name, object value, object comObject) + { + comObject.GetType().InvokeMember(name, BindingFlags.SetProperty, null, comObject, new object[] { value }); + } + + public object GetObject(IntPtr pUnk) + { + return Marshal.GetObjectForIUnknown(pUnk); + } + + public void ReleaseObject(object comObject) + { + Marshal.ReleaseComObject(comObject); + } + + public bool HasProperty(string name, object comObject) + { + return ExcelDna.ComInterop.DispatchHelper.HasProperty(comObject, name); + } + } +} diff --git a/Source/ExcelDna.Integration/ComInterop/Util.cs b/Source/ExcelDna.Integration/ComInterop/Util.cs new file mode 100644 index 00000000..2f0119d8 --- /dev/null +++ b/Source/ExcelDna.Integration/ComInterop/Util.cs @@ -0,0 +1,15 @@ +namespace ExcelDna.Integration.ComInterop +{ + internal static class Util + { + private static TypeAdapter typeAdapter = new TypeAdapter(); + + public static IType TypeAdapter + { + get + { + return NativeAOT.IsActive ? NativeAOT.TypeAdapter : typeAdapter; + } + } + } +} From 47b80098c1d9b0f102c032e4ebcd6b744e3f3119 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sat, 22 Mar 2025 16:17:23 +0500 Subject: [PATCH 32/60] Cleaned ExcelDnaUtil. --- Source/ExcelDna.Integration/ComInterop/TypeAdapter.cs | 11 +++++++---- Source/ExcelDna.Integration/Excel.cs | 4 ---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Source/ExcelDna.Integration/ComInterop/TypeAdapter.cs b/Source/ExcelDna.Integration/ComInterop/TypeAdapter.cs index 21e03252..9ed6186c 100644 --- a/Source/ExcelDna.Integration/ComInterop/TypeAdapter.cs +++ b/Source/ExcelDna.Integration/ComInterop/TypeAdapter.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.Reflection; using System.Runtime.InteropServices; using CLSID = System.Guid; @@ -7,14 +8,16 @@ namespace ExcelDna.Integration.ComInterop { internal class TypeAdapter : IType { + private static readonly CultureInfo _enUsCulture = new CultureInfo(1033); + public object GetProperty(string name, object comObject) { - return comObject.GetType().InvokeMember(name, BindingFlags.GetProperty, null, comObject, null); + return comObject.GetType().InvokeMember(name, BindingFlags.GetProperty, null, comObject, null, _enUsCulture); } public object GetIndex(int i, object comObject) { - return comObject.GetType().InvokeMember("", BindingFlags.GetProperty, null, comObject, new object[] { i }); + return comObject.GetType().InvokeMember("", BindingFlags.GetProperty, null, comObject, new object[] { i }, _enUsCulture); } public bool Is(ref CLSID guid, object comObject) @@ -28,12 +31,12 @@ public bool Is(ref CLSID guid, object comObject) public object Invoke(string name, object[] args, object comObject) { - return comObject.GetType().InvokeMember(name, BindingFlags.InvokeMethod, null, comObject, args); + return comObject.GetType().InvokeMember(name, BindingFlags.InvokeMethod, null, comObject, args, _enUsCulture); } public void SetProperty(string name, object value, object comObject) { - comObject.GetType().InvokeMember(name, BindingFlags.SetProperty, null, comObject, new object[] { value }); + comObject.GetType().InvokeMember(name, BindingFlags.SetProperty, null, comObject, new object[] { value }, _enUsCulture); } public object GetObject(IntPtr pUnk) diff --git a/Source/ExcelDna.Integration/Excel.cs b/Source/ExcelDna.Integration/Excel.cs index 77b32279..be063f5f 100644 --- a/Source/ExcelDna.Integration/Excel.cs +++ b/Source/ExcelDna.Integration/Excel.cs @@ -454,7 +454,6 @@ private static object GetApplicationFromWindow(IntPtr hWndMain, bool allowProtec if (ComInterop.Util.TypeAdapter.HasProperty("Application", obj)) { app = ComInterop.Util.TypeAdapter.GetProperty("Application", obj); - //app = obj.GetType().InvokeMember("Application", BindingFlags.GetProperty, null, obj, null, _enUsCulture); } else { @@ -465,9 +464,7 @@ private static object GetApplicationFromWindow(IntPtr hWndMain, bool allowProtec try { object workbook = ComInterop.Util.TypeAdapter.GetProperty("Workbook", obj); - //object workbook = obj.GetType().InvokeMember("Workbook", BindingFlags.GetProperty, null, obj, null, _enUsCulture); app = ComInterop.Util.TypeAdapter.GetProperty("Application", workbook); - //app = workbook.GetType().InvokeMember("Application", BindingFlags.GetProperty, null, workbook, null, _enUsCulture); // WARNING: The Application object returning from here can be problematic: // * It is a "sandbox" view of the Application that cannot Run macros or change workbooks @@ -496,7 +493,6 @@ private static object GetApplicationFromWindow(IntPtr hWndMain, bool allowProtec finally { ComInterop.Util.TypeAdapter.ReleaseObject(obj); - //Marshal.ReleaseComObject(obj); } // Continue enumeration? Only if the app is not yet found and protected flag not set. From 62e0517895f81df611c91c667baace0fac8cbe7d Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sat, 22 Mar 2025 16:59:28 +0500 Subject: [PATCH 33/60] Implemented getting COM index by name. --- .../ComInterfaces/DispatchObject.cs | 15 +++++++++++++-- .../ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs | 5 +++++ Source/ExcelDna.Integration/ComInterop/IType.cs | 1 + .../ComInterop/TypeAdapter.cs | 5 +++++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispatchObject.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispatchObject.cs index 26ef7d23..2b4d7c2e 100644 --- a/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispatchObject.cs +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispatchObject.cs @@ -58,11 +58,22 @@ public void SetProperty(string name, object value) public object? GetIndex(int i) { - var index = i; + var dispParams = new DispParams + { + rgvarg = [new Variant(i)], + rgdispidNamedArgs = 0, + cArgs = 1, + cNamedArgs = 0 + }; + return InvokeWrapper("Item", INVOKEKIND.INVOKE_PROPERTYGET, dispParams); + } + + public object? GetIndex(string name) + { var dispParams = new DispParams { - rgvarg = [new Variant(index)], + rgvarg = [new Variant(name)], rgdispidNamedArgs = 0, cArgs = 1, cNamedArgs = 0 diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs b/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs index 58789787..c9109346 100644 --- a/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs +++ b/Source/ExcelDna.COMWrappers.NativeAOT/TypeAdapter.cs @@ -15,6 +15,11 @@ public object GetIndex(int i, object comObject) return (comObject as DispatchObject)!.GetIndex(i)!; } + public object GetIndex(string name, object comObject) + { + return (comObject as DispatchObject)!.GetIndex(name)!; + } + public bool Is(ref Guid guid, object comObject) { return (comObject as DispatchObject)!.HasInterface(ref guid); diff --git a/Source/ExcelDna.Integration/ComInterop/IType.cs b/Source/ExcelDna.Integration/ComInterop/IType.cs index c31b7124..df96c0eb 100644 --- a/Source/ExcelDna.Integration/ComInterop/IType.cs +++ b/Source/ExcelDna.Integration/ComInterop/IType.cs @@ -11,6 +11,7 @@ public interface IType object GetProperty(string name, object comObject); void SetProperty(string name, object value, object comObject); object GetIndex(int i, object comObject); + object GetIndex(string name, object comObject); object Invoke(string name, object[] args, object comObject); bool Is(ref Guid guid, object comObject); } diff --git a/Source/ExcelDna.Integration/ComInterop/TypeAdapter.cs b/Source/ExcelDna.Integration/ComInterop/TypeAdapter.cs index 9ed6186c..7d803943 100644 --- a/Source/ExcelDna.Integration/ComInterop/TypeAdapter.cs +++ b/Source/ExcelDna.Integration/ComInterop/TypeAdapter.cs @@ -20,6 +20,11 @@ public object GetIndex(int i, object comObject) return comObject.GetType().InvokeMember("", BindingFlags.GetProperty, null, comObject, new object[] { i }, _enUsCulture); } + public object GetIndex(string name, object comObject) + { + return comObject.GetType().InvokeMember("", BindingFlags.GetProperty, null, comObject, new object[] { name }, _enUsCulture); + } + public bool Is(ref CLSID guid, object comObject) { IntPtr pUnk = Marshal.GetIUnknownForObject(comObject); From b651174efdd1ecf092a17a486ae1b63d9a877372 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sat, 22 Mar 2025 19:26:31 +0500 Subject: [PATCH 34/60] Extended TypeAdapter usage to all ExcelCommandBars methods. --- .../ExcelDna.Integration/ExcelCommandBars.cs | 181 ++++++------------ 1 file changed, 55 insertions(+), 126 deletions(-) diff --git a/Source/ExcelDna.Integration/ExcelCommandBars.cs b/Source/ExcelDna.Integration/ExcelCommandBars.cs index 2dbd918e..d555843a 100644 --- a/Source/ExcelDna.Integration/ExcelCommandBars.cs +++ b/Source/ExcelDna.Integration/ExcelCommandBars.cs @@ -45,26 +45,10 @@ public static class ExcelCommandBarUtil // List of loaded CustomUI static List loadedCustomUIs = new List(); - //static Util util = new Util(); - - //private class Util : ICommandBarUtil - //{ - // public ICommandBars GetCommandBars() - // { - // return ExcelCommandBarUtil.GetCommandBars(); - // } - //} - - //public static ICommandBarUtil GetUtil() - //{ - // return util; - //} - // Helper to call Application.CommandBars public static CommandBars GetCommandBars() { Application excelApp = new Application(ExcelDnaUtil.ApplicationObject); - //Application excelApp = new Application(NativeAOT.IsActive ? NativeAOT.ExcelApplication : ExcelDnaUtil.Application); return excelApp.CommandBars; } @@ -470,20 +454,18 @@ private static void ApplyControlAttribute(CommandBarControl control, string attr private class Application { object _object; - //Type _type; public Application(object application) { _object = application; - // _type = _object.GetType(); } public CommandBars CommandBars { get { - // object commandBars = _type.InvokeMember("CommandBars", BindingFlags.GetProperty, null, _object, null); - return new CommandBars(ComInterop.Util.TypeAdapter.GetProperty("CommandBars", _object)); + object commandBars = ComInterop.Util.TypeAdapter.GetProperty("CommandBars", _object); + return new CommandBars(commandBars); } } } @@ -505,12 +487,12 @@ The CommandBarComboBox control exposes a Change event that is triggered when a u public class CommandBar { object ComObject; - Type ComObjectType; + ComInterop.IType ComObjectType; internal CommandBar(object commandBar) { ComObject = commandBar; - ComObjectType = ComObject.GetType(); + ComObjectType = ComInterop.Util.TypeAdapter; } public object GetComObject() @@ -522,8 +504,7 @@ public CommandBarControls Controls { get { - object controls = ComInterop.Util.TypeAdapter.GetProperty("Controls", ComObject); - //object controls = ComObjectType.InvokeMember("Controls", BindingFlags.GetProperty, null, ComObject, null); + object controls = ComObjectType.GetProperty("Controls", ComObject); return new CommandBarControls(controls); } } @@ -532,7 +513,7 @@ public string Name { get { - object controls = ComObjectType.InvokeMember("Name", BindingFlags.GetProperty, null, ComObject, null); + object controls = ComObjectType.GetProperty("Name", ComObject); return controls.ToString(); } } @@ -541,37 +522,36 @@ public bool Visible { get { - return (bool)ComObjectType.InvokeMember("Visible", BindingFlags.GetProperty, null, ComObject, null); + return (bool)ComObjectType.GetProperty("Visible", ComObject); } set { - ComObjectType.InvokeMember("Visible", BindingFlags.SetProperty, null, ComObject, new object[] { value }); + ComObjectType.SetProperty("Visible", value, ComObject); } } public CommandBarControl FindControl(object type, object id, object tag, object visible, object recursive) { - object result = ComObjectType.InvokeMember("FindControl", BindingFlags.InvokeMethod, null, ComObject, new object[] { type, id, tag, visible, recursive }); + object result = ComObjectType.Invoke("FindControl", new object[] { type, id, tag, visible, recursive }, ComObject); if (result == null) return null; return new CommandBarControl(result); } public void Delete() { - ComObjectType.InvokeMember("Delete", BindingFlags.InvokeMethod, null, ComObject, null); + ComObjectType.Invoke("Delete", null, ComObject); } - } public class CommandBars { object _object; - Type _type; + ComInterop.IType _type; internal CommandBars(object commandBars) { _object = commandBars; - _type = _object.GetType(); + _type = ComInterop.Util.TypeAdapter; } public object GetComObject() @@ -581,7 +561,7 @@ public object GetComObject() public CommandBar Add(string name, MsoBarPosition barPosition) { - object commandBar = _type.InvokeMember("Add", BindingFlags.InvokeMethod, null, _object, new object[] { name, barPosition, Type.Missing, true }); + object commandBar = _type.Invoke("Add", new object[] { name, barPosition, Type.Missing, true }, _object); CommandBar cb = new CommandBar(commandBar); cb.Visible = true; return new CommandBar(commandBar); @@ -591,7 +571,7 @@ public CommandBar this[string name] { get { - object commandBar = _type.InvokeMember("", BindingFlags.GetProperty, null, _object, new object[] { name }); + object commandBar = _type.GetIndex(name, _object); return new CommandBar(commandBar); } } @@ -600,8 +580,7 @@ public CommandBar this[int i] { get { - object commandBar = ComInterop.Util.TypeAdapter.GetIndex(i, _object); - //object commandBar = _type.InvokeMember("", BindingFlags.GetProperty, null, _object, new object[] { i }); + object commandBar = _type.GetIndex(i, _object); return new CommandBar(commandBar); } } @@ -610,7 +589,7 @@ public int Count { get { - object i = _type.InvokeMember("Count", BindingFlags.GetProperty, null, _object, null); + object i = _type.GetProperty("Count", _object); return Convert.ToInt32(i); } } @@ -633,12 +612,12 @@ public class CommandBarControl private static Guid guidCommandBarComboBox = new Guid("000C030C-0000-0000-C000-000000000046"); internal protected object ComObject; - internal protected Type ComObjectType; + internal protected ComInterop.IType ComObjectType; internal CommandBarControl(object commandBarControl) { ComObject = commandBarControl; - ComObjectType = ComObject.GetType(); + ComObjectType = ComInterop.Util.TypeAdapter; } internal static CommandBarControl CreateCommandBarControl(MsoControlType controlType, object commandBarControl) @@ -662,52 +641,17 @@ internal static CommandBarControl CreateCommandBarControl(MsoControlType control internal static CommandBarControl CreateCommandBarControl(object commandBarControl) { if (ComInterop.Util.TypeAdapter.Is(ref guidCommandBarButton, commandBarControl)) - { - System.Diagnostics.Trace.WriteLine("[CreateCommandBarControl] is CommandBarButton"); return new CommandBarButton(commandBarControl); - } if (ComInterop.Util.TypeAdapter.Is(ref guidCommandBarPopup, commandBarControl)) - { - System.Diagnostics.Trace.WriteLine("[CreateCommandBarControl] is CommandBarPopup"); return new CommandBarPopup(commandBarControl); - } if (ComInterop.Util.TypeAdapter.Is(ref guidCommandBarComboBox, commandBarControl)) - { - System.Diagnostics.Trace.WriteLine("[CreateCommandBarControl] is CommandBarComboBox"); return new CommandBarComboBox(commandBarControl); - } - - //IntPtr pUnk = Marshal.GetIUnknownForObject(commandBarControl); - - //IntPtr pButton; - //Marshal.QueryInterface(pUnk, ref guidCommandBarButton, out pButton); - //if (pButton != IntPtr.Zero) - //{ - // return new CommandBarButton(commandBarControl); - //} - - //IntPtr pPopup; - //Marshal.QueryInterface(pUnk, ref guidCommandBarPopup, out pPopup); - //if (pPopup != IntPtr.Zero) - //{ - // return new CommandBarPopup(commandBarControl); - //} - - //IntPtr pComboBox; - //Marshal.QueryInterface(pUnk, ref guidCommandBarPopup, out pComboBox); - //if (pComboBox != IntPtr.Zero) - //{ - // return new CommandBarComboBox(commandBarControl); - //} - - System.Diagnostics.Trace.WriteLine("[CreateCommandBarControl] is ???"); return new CommandBarControl(commandBarControl); } - public object GetComObject() { return ComObject; @@ -717,13 +661,11 @@ public string Caption { get { - return (string)ComInterop.Util.TypeAdapter.GetProperty("Caption", ComObject); - //return (string)ComObjectType.InvokeMember("Caption", BindingFlags.GetProperty, null, ComObject, null); + return (string)ComObjectType.GetProperty("Caption", ComObject); } set { - ComInterop.Util.TypeAdapter.SetProperty("Caption", value, ComObject); - //ComObjectType.InvokeMember("Caption", BindingFlags.SetProperty, null, ComObject, new object[] { value }); + ComObjectType.SetProperty("Caption", value, ComObject); } } @@ -731,11 +673,11 @@ public string Tag { get { - return (string)ComObjectType.InvokeMember("Tag", BindingFlags.GetProperty, null, ComObject, null); + return (string)ComObjectType.GetProperty("Tag", ComObject); } set { - ComObjectType.InvokeMember("Tag", BindingFlags.SetProperty, null, ComObject, new object[] { value }); + ComObjectType.SetProperty("Tag", value, ComObject); } } @@ -743,11 +685,11 @@ public string TooltipText { get { - return (string)ComObjectType.InvokeMember("TooltipText", BindingFlags.GetProperty, null, ComObject, null); + return (string)ComObjectType.GetProperty("TooltipText", ComObject); } set { - ComObjectType.InvokeMember("TooltipText", BindingFlags.SetProperty, null, ComObject, new object[] { value }); + ComObjectType.SetProperty("TooltipText", value, ComObject); } } @@ -755,13 +697,11 @@ public string OnAction { get { - return (string)ComObjectType.InvokeMember("OnAction", BindingFlags.GetProperty, null, ComObject, null); + return (string)ComObjectType.GetProperty("OnAction", ComObject); } set { - ComInterop.Util.TypeAdapter.SetProperty("OnAction", value, ComObject); - - //ComObjectType.InvokeMember("OnAction", BindingFlags.SetProperty, null, ComObject, new object[] { value }); + ComObjectType.SetProperty("OnAction", value, ComObject); } } @@ -769,11 +709,11 @@ public bool BeginGroup { get { - return (bool)ComObjectType.InvokeMember("BeginGroup", BindingFlags.GetProperty, null, ComObject, null); + return (bool)ComObjectType.GetProperty("BeginGroup", ComObject); } set { - ComObjectType.InvokeMember("BeginGroup", BindingFlags.SetProperty, null, ComObject, new object[] { value }); + ComObjectType.SetProperty("BeginGroup", value, ComObject); } } @@ -781,11 +721,11 @@ public bool Enabled { get { - return (bool)ComObjectType.InvokeMember("Enabled", BindingFlags.GetProperty, null, ComObject, null); + return (bool)ComObjectType.GetProperty("Enabled", ComObject); } set { - ComObjectType.InvokeMember("Enabled", BindingFlags.SetProperty, null, ComObject, new object[] { value }); + ComObjectType.SetProperty("Enabled", value, ComObject); } } @@ -793,11 +733,11 @@ public int Height { get { - return (int)ComObjectType.InvokeMember("Height", BindingFlags.GetProperty, null, ComObject, null); + return (int)ComObjectType.GetProperty("Height", ComObject); } set { - ComObjectType.InvokeMember("Height", BindingFlags.SetProperty, null, ComObject, new object[] { value }); + ComObjectType.SetProperty("Height", value, ComObject); } } @@ -805,11 +745,11 @@ public string HelpFile { get { - return (string)ComObjectType.InvokeMember("HelpFile", BindingFlags.GetProperty, null, ComObject, null); + return (string)ComObjectType.GetProperty("HelpFile", ComObject); } set { - ComObjectType.InvokeMember("HelpFile", BindingFlags.SetProperty, null, ComObject, new object[] { value }); + ComObjectType.SetProperty("HelpFile", value, ComObject); } } @@ -817,11 +757,11 @@ public int HelpContextId { get { - return (int)ComObjectType.InvokeMember("HelpContextId", BindingFlags.GetProperty, null, ComObject, null); + return (int)ComObjectType.GetProperty("HelpContextId", ComObject); } set { - ComObjectType.InvokeMember("HelpContextId", BindingFlags.SetProperty, null, ComObject, new object[] { value }); + ComObjectType.SetProperty("HelpContextId", value, ComObject); } } @@ -829,11 +769,11 @@ public bool Visible { get { - return (bool)ComObjectType.InvokeMember("Visible", BindingFlags.GetProperty, null, ComObject, null); + return (bool)ComObjectType.GetProperty("Visible", ComObject); } set { - ComObjectType.InvokeMember("Visible", BindingFlags.SetProperty, null, ComObject, new object[] { value }); + ComObjectType.SetProperty("Visible", value, ComObject); } } @@ -841,25 +781,25 @@ public int Index { get { - return (int)ComObjectType.InvokeMember("Index", BindingFlags.GetProperty, null, ComObject, null); + return (int)ComObjectType.GetProperty("Index", ComObject); } } public void Delete(object Temporary) { - ComObjectType.InvokeMember("Delete", BindingFlags.InvokeMethod, null, ComObject, new object[] { Temporary }); + ComObjectType.Invoke("Delete", new object[] { Temporary }, ComObject); } } public class CommandBarControls { object ComObject; - Type ComObjectTtpe; + ComInterop.IType ComObjectType; internal CommandBarControls(object commandBarControls) { ComObject = commandBarControls; - ComObjectTtpe = ComObject.GetType(); + ComObjectType = ComInterop.Util.TypeAdapter; } public object GetComObject() @@ -871,7 +811,7 @@ public CommandBarControl this[string name] { get { - object commandBarControl = ComObjectTtpe.InvokeMember("", BindingFlags.GetProperty, null, ComObject, new object[] { name }); + object commandBarControl = ComObjectType.GetIndex(name, ComObject); return CommandBarControl.CreateCommandBarControl(commandBarControl); } } @@ -880,18 +820,14 @@ public CommandBarControl this[int id] { get { - object commandBarControl = ComInterop.Util.TypeAdapter.GetIndex(id, ComObject); - - //object commandBarControl = ComObjectTtpe.InvokeMember( - //"", BindingFlags.GetProperty, null, ComObject, new object[] { id }); + object commandBarControl = ComObjectType.GetIndex(id, ComObject); return CommandBarControl.CreateCommandBarControl(commandBarControl); } } public int Count() { - object i = ComInterop.Util.TypeAdapter.GetProperty("Count", ComObject); - //object i = ComObjectTtpe.InvokeMember("Count", BindingFlags.GetProperty, null, ComObject, null); + object i = ComObjectType.GetProperty("Count", ComObject); return Convert.ToInt32(i); } @@ -916,10 +852,7 @@ internal CommandBarControl FindOrAdd(MsoControlType controlType, string name, ob } } - object /*CommandBarControl*/ newControl = ComInterop.Util.TypeAdapter.Invoke("Add", new object[] { controlType, Id, Parameter, Before, Temporary }, ComObject); - //object /*CommandBarControl*/ newControl = ComObjectTtpe.InvokeMember("Add", BindingFlags.InvokeMethod, null, ComObject, - // new object[] { controlType, Id, Parameter, Before, Temporary }); - + object /*CommandBarControl*/ newControl = ComObjectType.Invoke("Add", new object[] { controlType, Id, Parameter, Before, Temporary }, ComObject); return CommandBarControl.CreateCommandBarControl(controlType, newControl); } @@ -978,7 +911,6 @@ public CommandBarPopup AddPopup(string name, object before) return (CommandBarPopup)FindOrAdd(MsoControlType.msoControlPopup, name, 1, Type.Missing, beforeIndex, true); } - public CommandBarComboBox AddComboBox() { return AddComboBox(Type.Missing); @@ -1027,9 +959,8 @@ public void SetButtonImage(Bitmap buttonImage) // IDataObject oldContent = Clipboard.GetDataObject(); Clipboard.SetImage(buttonImage); - Type t = ComObject.GetType(); - t.InvokeMember("Style", BindingFlags.SetProperty, null, ComObject, new object[] { MsoButtonStyle.msoButtonIconAndCaption }); - t.InvokeMember("PasteFace", BindingFlags.InvokeMethod, null, ComObject, null); + ComObjectType.SetProperty("Style", MsoButtonStyle.msoButtonIconAndCaption, ComObject); + ComObjectType.Invoke("PasteFace", null, ComObject); Clipboard.Clear(); // Clipboard.SetDataObject(oldContent); } @@ -1038,11 +969,11 @@ public int FaceId { get { - return (int)ComObjectType.InvokeMember("FaceId", BindingFlags.GetProperty, null, ComObject, null); + return (int)ComObjectType.GetProperty("FaceId", ComObject); } set { - ComObjectType.InvokeMember("FaceId", BindingFlags.SetProperty, null, ComObject, new object[] { value }); + ComObjectType.SetProperty("FaceId", value, ComObject); } } @@ -1050,11 +981,11 @@ public MsoButtonStyle Style { get { - return (MsoButtonStyle)ComObjectType.InvokeMember("Style", BindingFlags.GetProperty, null, ComObject, null); + return (MsoButtonStyle)ComObjectType.GetProperty("Style", ComObject); } set { - ComObjectType.InvokeMember("Style", BindingFlags.SetProperty, null, ComObject, new object[] { value }); + ComObjectType.SetProperty("Style", value, ComObject); } } @@ -1062,11 +993,11 @@ public string ShortcutText { get { - return (string)ComObjectType.InvokeMember("ShortcutText", BindingFlags.GetProperty, null, ComObject, null); + return (string)ComObjectType.GetProperty("ShortcutText", ComObject); } set { - ComObjectType.InvokeMember("ShortcutText", BindingFlags.SetProperty, null, ComObject, new object[] { value }); + ComObjectType.SetProperty("ShortcutText", value, ComObject); } } @@ -1100,9 +1031,7 @@ public CommandBarControls Controls { get { - object controls = ComInterop.Util.TypeAdapter.GetProperty("Controls", ComObject); - - //object controls = ComObjectType.InvokeMember("Controls", BindingFlags.GetProperty, null, ComObject, null); + object controls = ComObjectType.GetProperty("Controls", ComObject); return new CommandBarControls(controls); } } From b1320dd096518002cb6479e514506c6c73450f7a Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sat, 22 Mar 2025 19:46:19 +0500 Subject: [PATCH 35/60] Cleaned ExcelDna.Integration. --- Source/ExcelDna.Integration/ICommandBars.cs | 17 ----------------- Source/ExcelDna.Integration/MenuManager.cs | 20 ++++++++++---------- 2 files changed, 10 insertions(+), 27 deletions(-) delete mode 100644 Source/ExcelDna.Integration/ICommandBars.cs diff --git a/Source/ExcelDna.Integration/ICommandBars.cs b/Source/ExcelDna.Integration/ICommandBars.cs deleted file mode 100644 index 3e5d7ae9..00000000 --- a/Source/ExcelDna.Integration/ICommandBars.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace ExcelDna.Integration.CustomUI -{ - public interface ICommandBar - { - - } - - public interface ICommandBars - { - ICommandBar this[string name] { get; } - } - - public interface ICommandBarUtil - { - ICommandBars GetCommandBars(); - } -} diff --git a/Source/ExcelDna.Integration/MenuManager.cs b/Source/ExcelDna.Integration/MenuManager.cs index 55ff1a0a..831e61b9 100644 --- a/Source/ExcelDna.Integration/MenuManager.cs +++ b/Source/ExcelDna.Integration/MenuManager.cs @@ -14,7 +14,7 @@ namespace ExcelDna.Integration /// TODO: Can we integrate with ExcelCommandBars? /// Hierarchical menus. /// - + // CAUTION: This 'internal' class is called via reflection by the ExcelDna Loader. [UsedImplicitly(ImplicitUseTargetFlags.WithMembers)] internal static class MenuManager @@ -86,9 +86,9 @@ public void AddCommandMenu(string commandName, string menuName, string menuText, // Throws Access violation exception Excel if I add a string to description or helptopic XlCall.Excel(XlCall.xlfAddMenu, 1.0 /*Worksheet and Macro sheet*/, new object[,] { { menuName, null, null, null, null}, - { menuText, commandName, - null/*shortcut_key (Mac Only)*/, - null, // mi.Description, + { menuText, commandName, + null/*shortcut_key (Mac Only)*/, + null, // mi.Description, null /*mi.HelpTopic*/} }); _addedMenus.Add(menuName); done = true; @@ -105,11 +105,11 @@ public void AddCommandMenu(string commandName, string menuName, string menuText, XlCall.Excel(XlCall.xlfAddCommand, 1.0 /*Worksheet and Macro sheet*/, menuName, - new object[] { - menuText, - commandName, - null/*shortcut_key (Mac Only)*/, - null, // mi.Description, + new object[] { + menuText, + commandName, + null/*shortcut_key (Mac Only)*/, + null, // mi.Description, null /*mi.HelpTopic*/}); _addedMenuEntries.Add(new MenuEntry(commandName, menuName, menuText)); } @@ -171,6 +171,7 @@ public void AddCommandMenu(string commandName, string menuName, string menuText, if (!_foundMenus.TryGetValue(menuName, out menu)) { // We've not seen this menu before + // Check if the menu exists CommandBars commandBars = ExcelCommandBarUtil.GetCommandBars(); CommandBar worksheetBar = commandBars[1]; @@ -218,7 +219,6 @@ public void AddCommandMenu(string commandName, string menuName, string menuText, } catch (Exception e) { - System.Diagnostics.Trace.WriteLine("[MenuManager.AddCommandMenu] " + e.ToString()); Logger.Initialization.Error(e, "MenuManager.AddCommandMenu Error"); } } From 9f6e9c74955185289a42a2a3190ea215e3b432ce Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sat, 22 Mar 2025 20:31:48 +0500 Subject: [PATCH 36/60] Added ExcelDna.COMWrappers.NativeAOT.dll to the package. --- Build/build.bat | 9 +++++---- .../ExcelDna.AddIn.NativeAOT.nuspec | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Build/build.bat b/Build/build.bat index 21721d26..b551fea8 100644 --- a/Build/build.bat +++ b/Build/build.bat @@ -22,7 +22,7 @@ copy /Y ..\Source\ExcelDnaPack\bin\Release\net6.0-windows\ExcelDnaPack.runtimeco if not exist "..\Package\ExcelDna.AddIn\tools\net462\" mkdir "..\Package\ExcelDna.AddIn\tools\net462\" if not exist "..\Package\ExcelDna.AddIn\tools\net6.0-windows\" mkdir "..\Package\ExcelDna.AddIn\tools\net6.0-windows\" if not exist "..\Package\ExcelDna.AddIn.NativeAOT\tools\" mkdir "..\Package\ExcelDna.AddIn.NativeAOT\tools\" -if not exist "..\Package\ExcelDna.AddIn.NativeAOT\lib\net6.0-windows\" mkdir "..\Package\ExcelDna.AddIn.NativeAOT\lib\net6.0-windows\" +if not exist "..\Package\ExcelDna.AddIn.NativeAOT\lib\net8.0-windows\" mkdir "..\Package\ExcelDna.AddIn.NativeAOT\lib\net8.0-windows\" if not exist "..\Package\ExcelDna.AddIn.NativeAOT\analyzers\dotnet\cs" mkdir "..\Package\ExcelDna.AddIn.NativeAOT\analyzers\dotnet\cs" copy /Y ..\Source\ExcelDna.AddIn.Tasks\bin\Release\net462\ExcelDna.AddIn.Tasks.dll ..\Package\ExcelDna.AddIn\tools\net462\ @@ -34,9 +34,10 @@ copy /Y ..\Source\ExcelDna.AddIn.Tasks\bin\Release\net462\System.Collections.Imm copy /Y ..\Source\ExcelDna.AddIn.Tasks\bin\Release\net6.0-windows\ExcelDna.AddIn.Tasks.dll ..\Package\ExcelDna.AddIn\tools\net6.0-windows\ copy /Y ..\Source\ExcelDna.AddIn.Tasks\bin\Release\net6.0-windows\ExcelDna.AddIn.Tasks.pdb ..\Package\ExcelDna.AddIn\tools\net6.0-windows\ -copy /Y "..\Source\ExcelDna.Integration\bin\Release\net6.0-windows\ExcelDna.Integration.dll" "..\Package\ExcelDna.AddIn.NativeAOT\lib\net6.0-windows\" -copy /Y "..\Source\ExcelDna.ManagedHost\bin\Release\net6.0-windows\ExcelDna.ManagedHost.dll" "..\Package\ExcelDna.AddIn.NativeAOT\lib\net6.0-windows\" -copy /Y "..\Source\ExcelDna.Loader\bin\Release\net6.0-windows\ExcelDna.Loader.dll" "..\Package\ExcelDna.AddIn.NativeAOT\lib\net6.0-windows\" +copy /Y "..\Source\ExcelDna.Integration\bin\Release\net6.0-windows\ExcelDna.Integration.dll" "..\Package\ExcelDna.AddIn.NativeAOT\lib\net8.0-windows\" +copy /Y "..\Source\ExcelDna.ManagedHost\bin\Release\net6.0-windows\ExcelDna.ManagedHost.dll" "..\Package\ExcelDna.AddIn.NativeAOT\lib\net8.0-windows\" +copy /Y "..\Source\ExcelDna.Loader\bin\Release\net6.0-windows\ExcelDna.Loader.dll" "..\Package\ExcelDna.AddIn.NativeAOT\lib\net8.0-windows\" +copy /Y "..\Source\ExcelDna.COMWrappers.NativeAOT\bin\Release\net8.0-windows\ExcelDna.COMWrappers.NativeAOT.dll" "..\Package\ExcelDna.AddIn.NativeAOT\lib\net8.0-windows\" copy /Y "..\Source\ExcelDna.SourceGenerator.NativeAOT\bin\Release\netstandard2.0\ExcelDna.SourceGenerator.NativeAOT.dll" "..\Package\ExcelDna.AddIn.NativeAOT\analyzers\dotnet\cs\" copy /Y "..\Source\ExcelDna.Host.NativeAOT\bin\Release\x64\ExcelDna.Host.NativeAOT.x64.xll" "..\Package\ExcelDna.AddIn.NativeAOT\tools\ExcelDnaNativeAOT64.xll" diff --git a/Package/ExcelDna.AddIn.NativeAOT/ExcelDna.AddIn.NativeAOT.nuspec b/Package/ExcelDna.AddIn.NativeAOT/ExcelDna.AddIn.NativeAOT.nuspec index cc05ab36..773b52d5 100644 --- a/Package/ExcelDna.AddIn.NativeAOT/ExcelDna.AddIn.NativeAOT.nuspec +++ b/Package/ExcelDna.AddIn.NativeAOT/ExcelDna.AddIn.NativeAOT.nuspec @@ -24,7 +24,7 @@ Excel-DNA is an independent project to integrate .NET into Excel. excel exceldna udf excel-dna - + @@ -40,9 +40,10 @@ - - - + + + + From 0cf482cff7f2009866aee603a063739aa7685f76 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sun, 23 Mar 2025 15:44:40 +0500 Subject: [PATCH 37/60] Load ExcelRibbon from add-in (work in progress). --- .../ComInterfaces/DispatchObject.cs | 24 +++++++++----- Source/ExcelDna.Integration/AssemblyLoader.cs | 8 ++--- .../ComInterop/ComRegistration.cs | 7 ++-- Source/ExcelDna.Integration/DnaLibrary.cs | 2 +- Source/ExcelDna.Integration/ExcelComAddIn.cs | 19 ++++++----- .../Generator.cs | 3 +- .../RibbonController.cs | 32 +++++++++++++++++++ 7 files changed, 67 insertions(+), 28 deletions(-) create mode 100644 Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/RibbonController.cs diff --git a/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispatchObject.cs b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispatchObject.cs index 2b4d7c2e..5e5dce48 100644 --- a/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispatchObject.cs +++ b/Source/ExcelDna.COMWrappers.NativeAOT/ComInterfaces/DispatchObject.cs @@ -84,15 +84,23 @@ public void SetProperty(string name, object value) public object? Invoke(string name, object[] args) { - Variant[] a = args.Select(i => new Variant(i)).ToArray(); - - var dispParams = new DispParams + DispParams dispParams; + if (args != null) { - rgvarg = a, - rgdispidNamedArgs = 0, - cArgs = a.Length, - cNamedArgs = 0 - }; + Variant[] a = args.Select(i => new Variant(i)).ToArray(); + + dispParams = new DispParams + { + rgvarg = a, + rgdispidNamedArgs = 0, + cArgs = a.Length, + cNamedArgs = 0 + }; + } + else + { + dispParams = new DispParams(); + } return InvokeWrapper(name, INVOKEKIND.INVOKE_FUNC, dispParams); } diff --git a/Source/ExcelDna.Integration/AssemblyLoader.cs b/Source/ExcelDna.Integration/AssemblyLoader.cs index 62880661..0979da92 100644 --- a/Source/ExcelDna.Integration/AssemblyLoader.cs +++ b/Source/ExcelDna.Integration/AssemblyLoader.cs @@ -35,8 +35,6 @@ public static void ProcessAssemblies( List rtdServerTypes, List comClassTypes) { - bool loadRibbons = (ExcelDnaUtil.ExcelVersion >= 12.0); - foreach (ExportedAssembly assembly in assemblies) { int initialObjectsCount = methods.Count + @@ -89,7 +87,7 @@ public static void ProcessAssemblies( GetExcelMethods(type, explicitExports, methods, excelFunctionsExtendedRegistration); GetExcelFunctionExecutionHandlerSelectors(type, excelFunctionExecutionHandlerSelectors); } - GetExcelAddIns(assembly, new TypeHelperDynamic(type), loadRibbons, addIns); + GetExcelAddIns(assembly, new TypeHelperDynamic(type), addIns); GetRtdServerTypes(type, rtdServerTypes, out isRtdServer); GetComClassTypes(assembly, type, attribs, isRtdServer, comClassTypes); } @@ -292,8 +290,10 @@ public class ExcelAddInInfo public DnaLibrary ParentDnaLibrary; } - static public void GetExcelAddIns(ExportedAssembly assembly, ITypeHelper t, bool loadRibbons, List addIns) + static public void GetExcelAddIns(ExportedAssembly assembly, ITypeHelper t, List addIns) { + bool loadRibbons = (ExcelDnaUtil.ExcelVersion >= 12.0); + // NOTE: We probably should have restricted this to public types, but didn't. Now it's too late. // So internal classes that implement IExcelAddIn are also loaded. try diff --git a/Source/ExcelDna.Integration/ComInterop/ComRegistration.cs b/Source/ExcelDna.Integration/ComInterop/ComRegistration.cs index 96f590f0..338d4520 100644 --- a/Source/ExcelDna.Integration/ComInterop/ComRegistration.cs +++ b/Source/ExcelDna.Integration/ComInterop/ComRegistration.cs @@ -559,16 +559,15 @@ protected override void Deregister() object SetAutomationSecurity(object value) { - CultureInfo ci = new CultureInfo(1033); - Type appType = _app.GetType(); + Integration.ComInterop.IType appType = Integration.ComInterop.Util.TypeAdapter; try { - var oldValue = appType.InvokeMember("AutomationSecurity", BindingFlags.GetProperty, null, _app, null, ci); + var oldValue = appType.GetProperty("AutomationSecurity", _app); if (oldValue.Equals(value)) // Careful...they're boxed ints return null; Logger.ComAddIn.Verbose("AutomationSecurityEnable - Setting Application.AutomationSecurity to {0}", value); - appType.InvokeMember("AutomationSecurity", BindingFlags.SetProperty, null, _app, new object[] { value }, ci); + appType.SetProperty("AutomationSecurity", value, _app); return oldValue; } catch (Exception ex) diff --git a/Source/ExcelDna.Integration/DnaLibrary.cs b/Source/ExcelDna.Integration/DnaLibrary.cs index b8899295..833d5af7 100644 --- a/Source/ExcelDna.Integration/DnaLibrary.cs +++ b/Source/ExcelDna.Integration/DnaLibrary.cs @@ -282,7 +282,7 @@ internal void Initialize() // Recursively get assemblies down .dna tree. _exportedAssemblies = GetAssemblies(dnaResolveRoot); AssemblyLoader.ProcessAssemblies(_exportedAssemblies, _methods, _excelParameterConversions, _excelFunctionProcessors, _excelFunctionsExtendedRegistration, _excelFunctionExecutionHandlerSelectors, _addIns, rtdServerTypes, comClassTypes); - NativeAOT.ExcelAddIns.ForEach(i => AssemblyLoader.GetExcelAddIns(null, i, false, _addIns)); + NativeAOT.ExcelAddIns.ForEach(i => AssemblyLoader.GetExcelAddIns(null, i, _addIns)); // Register RTD Server Types (i.e. remember that these types are available as RTD servers, with relevant ProgId etc.) RtdRegistration.RegisterRtdServerTypes(rtdServerTypes); diff --git a/Source/ExcelDna.Integration/ExcelComAddIn.cs b/Source/ExcelDna.Integration/ExcelComAddIn.cs index 5df9c125..1373e459 100644 --- a/Source/ExcelDna.Integration/ExcelComAddIn.cs +++ b/Source/ExcelDna.Integration/ExcelComAddIn.cs @@ -106,7 +106,7 @@ public virtual void OnBeginShutdown(ref Array custom) } #endregion } - + public static class ExcelComAddInHelper { // Com Add-ins loaded for Ribbons. @@ -162,11 +162,10 @@ public static void LoadComAddIn(ExcelComAddIn addIn) Logger.ComAddIn.Verbose("Getting Application object"); - object app = ExcelDnaUtil.Application; - Type appType = app.GetType(); + object app = ExcelDnaUtil.ApplicationObject; + ComInterop.IType typeAdapter = ComInterop.Util.TypeAdapter; Logger.ComAddIn.Verbose("Got Application object: " + app.GetType().ToString()); - CultureInfo ci = new CultureInfo(1033); object excelComAddIns; object comAddIn; @@ -188,12 +187,12 @@ public static void LoadComAddIn(ExcelComAddIn addIn) var dummyAddIn = new DummyComAddIn(); using (new SingletonClassFactoryRegistration(dummyAddIn, clsId)) { - excelComAddIns = appType.InvokeMember("COMAddIns", BindingFlags.GetProperty, null, app, null, ci); + excelComAddIns = typeAdapter.GetProperty("COMAddIns", app); // Debug.Print("Got COMAddins object: " + excelComAddIns.GetType().ToString()); - appType.InvokeMember("Update", BindingFlags.InvokeMethod, null, excelComAddIns, null, ci); + typeAdapter.Invoke("Update", null, excelComAddIns); // Debug.Print("Updated COMAddins object with AddIn registered"); - comAddIn = excelComAddIns.GetType().InvokeMember("Item", BindingFlags.InvokeMethod, null, excelComAddIns, new object[] { progId }, ci); + comAddIn = typeAdapter.Invoke("Item", new object[] { progId }, excelComAddIns); // Debug.Print("Got the COMAddin object: " + comAddIn.GetType().ToString()); // At this point Excel knows how to load our add-in by CLSID, so we could clean up the @@ -201,13 +200,13 @@ public static void LoadComAddIn(ExcelComAddIn addIn) // But this seems to lead to some distress - Excel has some assertion checked when // it updates the LoadBehavior after a successful load.... - object connectState = comAddIn.GetType().InvokeMember("Connect", BindingFlags.GetProperty, null, comAddIn, null, ci); - comAddIn.GetType().InvokeMember("Connect", BindingFlags.SetProperty, null, comAddIn, new object[] { false }, ci); + object connectState = typeAdapter.GetProperty("Connect", comAddIn); + typeAdapter.SetProperty("Connect", false, comAddIn); } // Swap out the dummy add-in for the real one using (new SingletonClassFactoryRegistration(addIn, clsId)) { - comAddIn.GetType().InvokeMember("Connect", BindingFlags.SetProperty, null, comAddIn, new object[] { true }, ci); + typeAdapter.SetProperty("Connect", true, comAddIn); } // Debug.Print("COMAddin is loaded."); loadedComAddIns.Add(comAddIn); diff --git a/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs b/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs index 71b640b4..5e0aa783 100644 --- a/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs +++ b/Source/ExcelDna.SourceGenerator.NativeAOT/Generator.cs @@ -85,7 +85,8 @@ public void OnVisitSyntaxNode(GeneratorSyntaxContext context) { if (context.SemanticModel.GetDeclaredSymbol(classSyntax) is ITypeSymbol typeSymbol) { - if (typeSymbol.AllInterfaces.Any(i => Util.GetFullTypeName(i) == "ExcelDna.Integration.IExcelAddIn")) + if (typeSymbol.AllInterfaces.Any(i => Util.GetFullTypeName(i) == "ExcelDna.Integration.IExcelAddIn") || + Util.GetBaseTypesAndThis(typeSymbol).Any(i => Util.GetFullTypeName(i) == "ExcelDna.Integration.CustomUI.ExcelRibbon")) { AddIns.Add(typeSymbol); } diff --git a/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/RibbonController.cs b/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/RibbonController.cs new file mode 100644 index 00000000..1f2d42fb --- /dev/null +++ b/Source/Tests/ExcelDna.AddIn.RuntimeTestsAOT/RibbonController.cs @@ -0,0 +1,32 @@ +using System.Runtime.InteropServices; +using System.Windows.Forms; +using ExcelDna.Integration.CustomUI; + +namespace ExcelDna.AddIn.RuntimeTestsAOT +{ + [ComVisible(true)] + public class RibbonController : ExcelRibbon + { + public override string GetCustomUI(string RibbonID) + { + return @" + + + + + +