Description: Bootstrapping in .Net (tested with .Net 6) fails, whereas bootstrapping in .Net Framework (tested with .Net Framework 4.8) succeeds. Consider this C# code: static int Main() { string programPath = GetProgramPath(); System.Environment.SetEnvironmentVariable( "UNO_PATH", programPath, System.EnvironmentVariableTarget.Process ); System.Environment.SetEnvironmentVariable( "URE_BOOTSTRAP", $"vnd.sun.star.pathname:{System.IO.Path.Combine(programPath, "fundamental.ini")}", System.EnvironmentVariableTarget.Process ); System.Environment.SetEnvironmentVariable( "PATH", $"{programPath}{System.IO.Path.PathSeparator}{System.Environment.GetEnvironmentVariable("PATH")}", System.EnvironmentVariableTarget.Process ); try { uno.util.Bootstrap.defaultBootstrap_InitialComponentContext(); System.Console.Out.WriteLine("OK!"); return 0; } catch (System.Exception x) { System.Console.Error.WriteLine(x.GetType().FullName); System.Console.Error.WriteLine(x.Message); System.Console.Error.WriteLine(x.StackTrace); return 1; } } static string GetProgramPath() { var programPath = Microsoft.Win32.Registry.GetValue( Microsoft.Win32.Registry.LocalMachine.Name + @"\SOFTWARE\LibreOffice\UNO\InstallPath", "", null ) as string; if (string.IsNullOrEmpty(programPath)) { throw new System.Exception("Failed to detect the program path"); } return programPath; } When executed with .Net Framework 4.8 everything works just fine. When executed with .Net 6 we have: System.InvalidOperationException Handle is not initialized. at System.Runtime.InteropServices.GCHandle.FromIntPtr(IntPtr value) at uno.util.to_cli<class com::sun::star::uno::XComponentContext>(Reference<com::sun::star::uno::XComponentContext>* x) at uno.util.Bootstrap.defaultBootstrap_InitialComponentContext(String ini_file, IDictionaryEnumerator bootstrap_parameters) at uno.util.Bootstrap.defaultBootstrap_InitialComponentContext() at ConsoleDotNetFramework.Program.Main() in Program.cs:line 26 I tested it with LibreOffice 7.3.1.3 and with a fresh built of master (as of 2022-03-28): same results. I also tested it in a Windows Sandbox: same results. Steps to Reproduce: 1. Create a .Net (not .Net Framework) project 2. Add references to the DLLs that come with the SDK 3. Call uno.util.Bootstrap.defaultBootstrap_InitialComponentContext(); Actual Results: defaultBootstrap_InitialComponentContext throws a System.InvalidOperationException exception: Message: Handle is not initialized. Stack trace: at System.Runtime.InteropServices.GCHandle.FromIntPtr(IntPtr value) at uno.util.to_cli<class com::sun::star::uno::XComponentContext>(Reference<com::sun::star::uno::XComponentContext>* x) at uno.util.Bootstrap.defaultBootstrap_InitialComponentContext(String ini_file, IDictionaryEnumerator bootstrap_parameters) at uno.util.Bootstrap.defaultBootstrap_InitialComponentContext() Expected Results: defaultBootstrap_InitialComponentContext should return a unoidl.com.sun.star.uno.XComponentContext instance without throwing an exception. Reproducible: Always User Profile Reset: Yes Additional Info: I published a simple Visual Studio solution to showcase this: see https://github.com/mlocati/libreoffice-uno-dotnet The .Net project fails, the .NetFramework project succeeds (with exactly the same code)
Does anyone fixing this error or can say something about it?
I repro the problem both with net6, and netcoreapp3.1, using x64 platform. Also the same is I use 'uno.util.Bootstrap.bootstrap()' instead of 'uno.util.Bootstrap.defaultBootstrap_InitialComponentContext()'. If you enable the mixed-mode debugging (allowing to debug native code), and put breakpoint to mediate_mapInterface (cppu/source/uno/lbmap.cxx), then the problem happens in the call to (*pUno2To->mapInterface)( pUno2To, ppOut, pUnoI, pInterfaceTypeDescr ); where VS reports that mapInterface points to {cli_uno.dll!Mapping_uno2cli}, but you can't step into it from the code editor, and when you use disassembly to step into, it looks like a no-op, instead of the expected Mapping_uno2cli from cli_ure/source/uno_bridge/cli_bridge.cxx. Trying to put breakpoints in the latter function (or anywhere in the file) is impossible (the debugger tells that "No executable code of the debugger's target code type is associated with this line ..."). Since the actually called code is a no-op, the ppOut will still contain a nullptr upon returning to mediate_mapInterface, and then the "Handle is not initialized" happens. And here I get stuck, having no experience with all this machinery. Stephan, do you have an idea?
Bug is still exist in 7.6.2.1 version of SDK. I'm using .NET 7.
I confirm this bug for Version: 7.6.4.1 (X86_64) / LibreOffice Community Build ID: e19e193f88cd6c0525a17fb7a176ed8e6a3e2aa1 CPU threads: 2; OS: Windows 10.0 Build 22621; UI render: Skia/Raster; VCL: win Locale: de-DE (de_DE); UI: de-DE Calc: threaded Since the bug is not yet assigned to anybody since one and a half year it seems that the issue is not with high priority. My question is if there is a workaround?
https://learn.microsoft.com/en-us/dotnet/core/porting/cpp-cli It seems to me, that the preferrable way to move forward would be to re-implement the cli assemblies in LibreOffice in C# or other language that doesn't have these limitations (if it is possible). Or to have a separate set of assemblies for .NET, as we have for .NET Framework.
FTR: running the DotNet6 config from the solution from comment 0, putting a breakpoint to loadEnv (cppu/source/uno/lbenv.cxx), when it gets called for "cli_uno", in the call to (*fpInit)( pEnv ), it will load the cli_uno.dll, which will load C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll (seen in VS debugger's Output window); shortly after, an exception is thrown (no idea if it's important); and then, some assemblies for 4.0 will load, then unload; and finally, cli_uno.dll will unload. Neither before, nor after, it will be impossible to put a breakpoint to uno_initEnvironment in cli_ure/source/uno_bridge/cli_bridge.cxx. When debugging DotNetFramework4.8 config, the uno_initEnvironment in cli_bridge.cxx will even be called directly, not from loadEnv.
Since .NET Framework and .NET Core are now merged to .NET and will not see new development anymore, it would make sense to take in consideration to go this way also with LO. Otherwise coming releases of LO will not work with .NET. How to deal with backward compatibility is another question.