Excel-DNA / ExcelDna

Excel-DNA - Free and easy .NET for Excel. This repository contains the core Excel-DNA library.
https://excel-dna.net
zlib License
1.26k stars 270 forks source link

native runtime library is not found when packed. #679

Closed grleachman closed 3 months ago

grleachman commented 3 months ago

Hello, I have read through some of the documentation around adding references in .net 6 and have upgraded to vs 1.7 of excel.dna.

However I still have a problem with a native library I am trying to use.

Specifically I am using msalruntime.dll

in the output folder this is found in /runtimes/win-x64/native/msalruntime.dll

looking in the MyAddin.deps.json file I have found a reference to the file under "targets": { ".NETCoreApp,Version=v6.0": { "Microsoft.Identity.Client.NativeInterop/0.13.14": { "runtimeTargets": { "runtimes/win-x64/native/msalruntime.dll": { "rid": "win-x64", "assetType": "native", "fileVersion": "0.0.0.0"

and looking in the logs of the build I have the following entry: 2>PackExcelAddIn: -> Updating resource: Type: NATIVE_LIBRARY_LZMA, Name: MSALRUNTIME.DLL, Source: Native deps.json, Length: 851752

when I load the unpacked.xll from bin\net6.0-windows folder the msal library is found. however when I load the packed.xll from bin\net6.0-windows\publish , the msal library is not found.

I can easily correct the problem by dropping the msalruntime.dll file into the same folder as the packed.xll file. However I would prefer not to have to do this.

Reading through the issues and discussion on this, it did not seem that I should be trying to add the file manually, as you seem to have gone to the effort of actually packing the native libraries.

Can you advise the best way for me to get around this problem, so that the file is in the packed.xll file. Many thanks

govert commented 3 months ago

I guess the problem has to do with how the native library is loaded. Excel-DNA overloads the LoadUnmanagedDll method of the AssemblyLoadContext that we create for the add-in. I think that libraries that P/Invoke or call LoadLibrary to load the native .dll will get routed to this event, and we should resolve to the packed native library (actually the file unpacked to the temp directory). The relevant code is here: https://github.com/Excel-DNA/ExcelDna/blob/c8d71708eb6355666cc9ab65e850ffcc291ab109/Source/ExcelDna.ManagedHost/ExcelDnaAssemblyLoadContext.cs#L44 and here https://github.com/Excel-DNA/ExcelDna/blob/c8d71708eb6355666cc9ab65e850ffcc291ab109/Source/ExcelDna.ManagedHost/AssemblyManager.cs#L136

You can confirm whether the file is extracted to the C:\Users\<User>\AppData\Local\Temp\ExcelDna.Host\<RandomGuid>\. I doubt it though, since it should resolve correctly if it were to get to the extract step.

I have seen .NET libraries that use their own mechanisms to try to find and load the right native .dll. Such probing might not feed through to the .NET runtime AssemblyLoadContext mechanism and cause the load to fail. A kind of hail-Mary approach you can try is to call LoadLibrary("msalruntime.dll") in your AutoOpen() hoping that if the library is already loaded into the process by the time the relevant managed code looks for it, the resolution might be successful.

This comment in a somewhat related discussion suggests there is an environment variable involved in the resolution, and they don't use LoadLibrary. https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/3740#issuecomment-1400384640 I'm not sure if you like to go down that route (the previous comment has a dead link that would be useful) to track down how the library is being detected and whether you can work around in your code, before the load happens.

If you made a small project that exhibits this problem, I'd be happy to look further.

grleachman commented 3 months ago

thank you and I see it's been raised as a bug here.

Happy to close this issue, as it's looking to be a bug in the Microsoft authentication library thanks for spotting that.

jmkinzer commented 3 months ago

Just wanted to comment that this was quite helpful as I recently had the same issue. I can confirm in a least my case pre-loading the library indeed worked. Note I didn't have luck using LoadLibrary for some reason but something like the following did the trick: NativeLibrary.Load("LIBSOMETHING.DLL", Assembly.GetExecutingAssembly(), DllImportSearchPath.ApplicationDirectory);