LO Version: 25.8.0.0.alpha0+ (X86_64) / LibreOffice Community
OS: Ubuntu 22.04
Greetings.
I built LibreOffice from source to be able to access the .NET bridge added last summer.
This bridge provides 2 methods in the Bootstrap
class: bootstrap
and defaultBootstrap_InitialComponentContext
, which are also available in some other bridges.
The first method creates its own LibreOffice process, connects to it via a pipe
and returns an XComponentContext
, from which you can get XDesktop2
and XComponentLoader
for further work with documents. This one working fine.
The second method creates a local XComponentContext
with which you can connect to a remote LibreOffice process using a pipe
or socket
. This also working fine but then you need to get the remote XComponentContext
, which is where the problem arises.
Following the logic from the Java and C++ code examples, I can correctly get the remote XComponentContext
, but then when trying to get XDesktop2
, an exception is thrown with the message:
could not map given type name com.sun.star.frame.XDesktop2 at /home/username/libregit/core/bridges/source/net_uno/net_base.cxx:230:
at com.sun.star.uno.native.NetEnvironment.ThrowError(String pWhere, String pMessage)
Both processes start with environment variables set. Is this a problem with the bridge implementation or are there some additional conditions that need to be met?
I tried different strategies to get the remote XComponentContext
but they all lead to the same result, here is one of them:
var unoUrl = "uno:socket,host=localhost,port=2083;urp;StarOffice.ServiceManager";
var localComponentContext = NativeBootstrap.defaultBootstrap_InitialComponentContext();
var urlResolver = UnoUrlResolver.create(localComponentContext);
var resolvedObject = urlResolver.resolve(unoUrl)
?? throw new UnoWrapperException("Provided initial object name unknown at server side");
var defaultServerContext = resolvedObject.query<XPropertySet>()
.getPropertyValue("DefaultContext")
.cast<XComponentContext>();
var desktop = Desktop.create(componentContext);
var componentLoader = desktop.query<XComponentLoader>();
All goes good until Desktop.create(componentContext)
line
Additional:
I am not very familiar with the LibreOffice source code, but after looking at the core/net_ure/source/bootstrap/bootstrap.cxx
file, I assumed that the problem might be that the received remote XComponentContext
is not mapped to .NET.
So I added a method to the .NET Bootstrap bridge source code that internally receives the remote XComponentContext
, maps it to .NET and returns it in this form. But this also did not give any results. The code for this method:
SAL_DLLPUBLIC_EXPORT IntPtr bootstrapFromUrl(const sal_Unicode* unoUrl,
const Context aContext)
{
try
{
OUString sConnectionString(unoUrl);
Reference< XComponentContext > xContext;
Reference< XComponentContext > xLocalContext(::cppu::defaultBootstrap_InitialComponentContext());
// create a URL resolver
Reference< bridge::XUnoUrlResolver > xUrlResolver(
bridge::UnoUrlResolver::create( xLocalContext ) );
// connect to office
xContext.set(
xUrlResolver->resolve( sConnectionString ), UNO_QUERY_THROW );
// Get a mapping between the C++ and .NET environments
Environment cpp_env(CPPU_CURRENT_LANGUAGE_BINDING_NAME);
Environment net_env(u"" UNO_LB_NET ""_ustr, new Context(aContext));
Mapping mapping(cpp_env.get(), net_env.get());
if (!mapping.is())
{
Reference<lang::XComponent> xComp(xContext, UNO_QUERY);
if (xComp.is())
{
xComp->dispose();
}
throw RuntimeException(u"could not get mapping between C++ and .NET"_ustr);
}
// Map the XComponentContext to a .NET proxy
return mapping.mapInterface(xContext.get(), cppu::UnoType<decltype(xContext)>::get());
}
catch (const Exception& exc)
{
SAL_WARN("net", ".NET bootstrap error: " << exc.Message);
aContext.throwError((u"" SAL_WHERE ""_ustr).getStr(), exc.Message.getStr());
return nullptr;
}
}