.NET Bindings: Native bridge for .NET
This patch includes all marshalling and proxy handling code on the .NET side as well as the native side needed for a fully functional UNO bridge. It also includes some changes and corrections to net_basetypes and netmaker needed for the bridge to work properly. It also includes the FirstUnoContact example in C# as demonstration. Change-Id: I406932938a4415d24408fb41ddfa7d8eeb5d1f94 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170916 Tested-by: Jenkins Reviewed-by: Hossein <hossein@libreoffice.org>
This commit is contained in:
parent
074714fab8
commit
c3c7b48fa9
38 changed files with 4155 additions and 68 deletions
|
@ -603,7 +603,10 @@ $(eval $(call gb_Helper_register_libraries_for_install,PLAINLIBS_URE,ure, \
|
|||
$(if $(filter MSC,$(COM)),$(if $(filter-out AARCH64_TRUE,$(CPUNAME)_$(CROSS_COMPILING)),cli_uno)) \
|
||||
) \
|
||||
i18nlangtag \
|
||||
$(if $(ENABLE_DOTNET),net_bootstrap) \
|
||||
$(if $(ENABLE_DOTNET), \
|
||||
net_bootstrap \
|
||||
net_uno \
|
||||
) \
|
||||
$(if $(ENABLE_JAVA), \
|
||||
java_uno \
|
||||
jpipe \
|
||||
|
|
33
bridges/Library_net_uno.mk
Normal file
33
bridges/Library_net_uno.mk
Normal file
|
@ -0,0 +1,33 @@
|
|||
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
|
||||
#
|
||||
# This file is part of the LibreOffice project.
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
|
||||
$(eval $(call gb_Library_Library,net_uno))
|
||||
|
||||
$(eval $(call gb_Library_use_udk_api,net_uno))
|
||||
|
||||
$(eval $(call gb_Library_set_include,net_uno,\
|
||||
-I$(SRCDIR)/bridges/source/net_uno \
|
||||
$$(INCLUDE) \
|
||||
))
|
||||
|
||||
$(eval $(call gb_Library_use_libraries,net_uno,\
|
||||
cppu \
|
||||
sal \
|
||||
salhelper \
|
||||
))
|
||||
|
||||
$(eval $(call gb_Library_add_exception_objects,net_uno,\
|
||||
bridges/source/net_uno/net_base \
|
||||
bridges/source/net_uno/net_bridge \
|
||||
bridges/source/net_uno/net_data \
|
||||
bridges/source/net_uno/net_func \
|
||||
bridges/source/net_uno/net_proxy \
|
||||
))
|
||||
|
||||
# vim: set noet sw=4 ts=4:
|
|
@ -11,6 +11,7 @@ $(eval $(call gb_Module_Module,bridges))
|
|||
|
||||
$(eval $(call gb_Module_add_targets,bridges,\
|
||||
Library_cpp_uno \
|
||||
$(if $(ENABLE_DOTNET),Library_net_uno) \
|
||||
$(if $(ENABLE_JAVA),\
|
||||
Jar_java_uno \
|
||||
Library_java_uno \
|
||||
|
|
234
bridges/source/net_uno/net_base.cxx
Normal file
234
bridges/source/net_uno/net_base.cxx
Normal file
|
@ -0,0 +1,234 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
||||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "net_base.hxx"
|
||||
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <o3tl/string_view.hxx>
|
||||
#include <rtl/ustring.hxx>
|
||||
#include <rtl/ustrbuf.hxx>
|
||||
|
||||
namespace net_uno
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const std::unordered_map<std::u16string_view, std::u16string_view> s_typeNames{
|
||||
{ u"System.Void", u"void" },
|
||||
{ u"System.Boolean", u"boolean" },
|
||||
{ u"System.Char", u"char" },
|
||||
{ u"System.SByte", u"byte" },
|
||||
{ u"System.Int16", u"short" },
|
||||
{ u"System.UInt16", u"unsigned short" },
|
||||
{ u"System.Int32", u"long" },
|
||||
{ u"System.UInt32", u"unsigned long" },
|
||||
{ u"System.Int64", u"hyper" },
|
||||
{ u"System.UInt64", u"unsigned hyper" },
|
||||
{ u"System.Single", u"float" },
|
||||
{ u"System.Double", u"double" },
|
||||
{ u"System.String", u"string" },
|
||||
{ u"System.Type", u"type" },
|
||||
{ u"com.sun.star.uno.Any", u"any" },
|
||||
{ u"com.sun.star.uno.UnoException", u"com.sun.star.uno.Exception" },
|
||||
{ u"com.sun.star.uno.IQueryInterface", u"com.sun.star.uno.XInterface" },
|
||||
};
|
||||
|
||||
const std::unordered_map<OUString, typelib_TypeClass> s_typeClasses{
|
||||
{ u"System.Void"_ustr, typelib_TypeClass_VOID },
|
||||
{ u"System.Boolean"_ustr, typelib_TypeClass_BOOLEAN },
|
||||
{ u"System.Char"_ustr, typelib_TypeClass_CHAR },
|
||||
{ u"System.SByte"_ustr, typelib_TypeClass_BYTE },
|
||||
{ u"System.Int16"_ustr, typelib_TypeClass_SHORT },
|
||||
{ u"System.UInt16"_ustr, typelib_TypeClass_UNSIGNED_SHORT },
|
||||
{ u"System.Int32"_ustr, typelib_TypeClass_LONG },
|
||||
{ u"System.UInt32"_ustr, typelib_TypeClass_UNSIGNED_LONG },
|
||||
{ u"System.Int64"_ustr, typelib_TypeClass_HYPER },
|
||||
{ u"System.UInt64"_ustr, typelib_TypeClass_UNSIGNED_HYPER },
|
||||
{ u"System.Single"_ustr, typelib_TypeClass_FLOAT },
|
||||
{ u"System.Double"_ustr, typelib_TypeClass_DOUBLE },
|
||||
{ u"System.String"_ustr, typelib_TypeClass_STRING },
|
||||
{ u"System.Type"_ustr, typelib_TypeClass_TYPE },
|
||||
{ u"com.sun.star.uno.Any"_ustr, typelib_TypeClass_ANY },
|
||||
};
|
||||
|
||||
void map_uno_type_to_net(typelib_TypeDescriptionReference* pTDRef, OUStringBuffer& buffer)
|
||||
{
|
||||
switch (pTDRef->eTypeClass)
|
||||
{
|
||||
case typelib_TypeClass_VOID:
|
||||
buffer.append(u"System.Void");
|
||||
break;
|
||||
case typelib_TypeClass_CHAR:
|
||||
buffer.append(u"System.Char");
|
||||
break;
|
||||
case typelib_TypeClass_BOOLEAN:
|
||||
buffer.append(u"System.Boolean");
|
||||
break;
|
||||
case typelib_TypeClass_BYTE:
|
||||
buffer.append(u"System.SByte");
|
||||
break;
|
||||
case typelib_TypeClass_SHORT:
|
||||
buffer.append(u"System.Int16");
|
||||
break;
|
||||
case typelib_TypeClass_UNSIGNED_SHORT:
|
||||
buffer.append(u"System.UInt16");
|
||||
break;
|
||||
case typelib_TypeClass_LONG:
|
||||
buffer.append(u"System.Int32");
|
||||
break;
|
||||
case typelib_TypeClass_UNSIGNED_LONG:
|
||||
buffer.append(u"System.UInt32");
|
||||
break;
|
||||
case typelib_TypeClass_HYPER:
|
||||
buffer.append(u"System.Int64");
|
||||
break;
|
||||
case typelib_TypeClass_UNSIGNED_HYPER:
|
||||
buffer.append(u"System.UInt64");
|
||||
break;
|
||||
case typelib_TypeClass_FLOAT:
|
||||
buffer.append(u"System.Single");
|
||||
break;
|
||||
case typelib_TypeClass_DOUBLE:
|
||||
buffer.append(u"System.Double");
|
||||
break;
|
||||
case typelib_TypeClass_STRING:
|
||||
buffer.append(u"System.String");
|
||||
break;
|
||||
case typelib_TypeClass_TYPE:
|
||||
buffer.append(u"System.Type");
|
||||
break;
|
||||
case typelib_TypeClass_ANY:
|
||||
buffer.append(u"com.sun.star.uno.Any");
|
||||
break;
|
||||
|
||||
case typelib_TypeClass_ENUM:
|
||||
case typelib_TypeClass_EXCEPTION:
|
||||
// These have the same name on both sides
|
||||
buffer.append(OUString::unacquired(&pTDRef->pTypeName));
|
||||
break;
|
||||
|
||||
case typelib_TypeClass_STRUCT:
|
||||
// These have the same name on both sides
|
||||
// TODO: What about polymorphic structs? Merge this with above cases if fine
|
||||
buffer.append(OUString::unacquired(&pTDRef->pTypeName));
|
||||
break;
|
||||
|
||||
case typelib_TypeClass_INTERFACE:
|
||||
{
|
||||
// These have the same name on both sides
|
||||
if (u"com.sun.star.uno.XInterface"_ustr.equals(pTDRef->pTypeName))
|
||||
// Except XInterface, which does not exist on the .NET side
|
||||
buffer.append(u"com.sun.star.uno.IQueryInterface");
|
||||
else
|
||||
buffer.append(OUString::unacquired(&pTDRef->pTypeName));
|
||||
break;
|
||||
}
|
||||
|
||||
case typelib_TypeClass_SEQUENCE:
|
||||
{
|
||||
TypeDescHolder seqType(pTDRef);
|
||||
typelib_TypeDescriptionReference* pElementTDRef
|
||||
= reinterpret_cast<typelib_IndirectTypeDescription*>(seqType.get())->pType;
|
||||
map_uno_type_to_net(pElementTDRef, buffer);
|
||||
buffer.append(u"[]");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
throw BridgeRuntimeError(SAL_WHERE, "could not map given type info "
|
||||
+ OUString::unacquired(&pTDRef->pTypeName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void map_net_type_to_uno(std::u16string_view sTypeName, OUStringBuffer& buffer)
|
||||
{
|
||||
size_t bracketsStart = sTypeName.find_last_not_of(u"[]");
|
||||
bool isSequence = bracketsStart != std::u16string_view::npos;
|
||||
std::u16string_view sBrackets = isSequence ? sTypeName.substr(bracketsStart + 1) : u"";
|
||||
std::u16string_view sFullName = isSequence ? sTypeName.substr(0, bracketsStart + 1) : sTypeName;
|
||||
|
||||
size_t genericsStart = sFullName.find_first_of(u'<');
|
||||
size_t genericsEnd = sFullName.find_last_of(u'>');
|
||||
bool hasGenerics = genericsStart != std::u16string_view::npos;
|
||||
std::u16string_view sGenericParams
|
||||
= hasGenerics ? sFullName.substr(genericsStart + 1, genericsEnd - genericsStart - 1) : u"";
|
||||
std::u16string_view sBaseName = hasGenerics ? sFullName.substr(0, genericsStart) : sFullName;
|
||||
|
||||
// Sequence brackets go at the beginning of UNO name
|
||||
for (size_t i = 0; i < sBrackets.size() / 2; i++)
|
||||
buffer.append(u"[]");
|
||||
|
||||
// Builtin types
|
||||
auto it = s_typeNames.find(sBaseName);
|
||||
if (it != s_typeNames.end())
|
||||
{
|
||||
buffer.append(it->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.append(sBaseName);
|
||||
if (hasGenerics)
|
||||
{
|
||||
buffer.append(u'<');
|
||||
for (size_t i = 0; i != std::string_view::npos;)
|
||||
{
|
||||
std::u16string_view genericParam(o3tl::getToken(sGenericParams, u',', i));
|
||||
map_net_type_to_uno(genericParam, buffer);
|
||||
if (i != std::string_view::npos)
|
||||
buffer.append(u',');
|
||||
}
|
||||
buffer.append(u'>');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OUString map_uno_type_to_net(typelib_TypeDescriptionReference* pTDRef)
|
||||
{
|
||||
OUStringBuffer buffer;
|
||||
map_uno_type_to_net(pTDRef, buffer);
|
||||
return buffer.makeStringAndClear();
|
||||
}
|
||||
|
||||
typelib_TypeDescriptionReference* map_net_type_to_uno(const OUString& sTypeName)
|
||||
{
|
||||
typelib_TypeDescriptionReference* retVal = nullptr;
|
||||
|
||||
// Simple types
|
||||
auto it = s_typeClasses.find(sTypeName);
|
||||
if (it != s_typeClasses.end())
|
||||
{
|
||||
retVal = *typelib_static_type_getByTypeClass(it->second);
|
||||
typelib_typedescriptionreference_acquire(retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
// Complex types (structs, interfaces, sequences)
|
||||
OUStringBuffer buffer;
|
||||
map_net_type_to_uno(sTypeName, buffer);
|
||||
OUString convertedName = buffer.makeStringAndClear();
|
||||
|
||||
typelib_TypeDescription* pTD = nullptr;
|
||||
typelib_typedescription_getByName(&pTD, convertedName.pData);
|
||||
if (pTD)
|
||||
{
|
||||
retVal = pTD->pWeakRef;
|
||||
typelib_typedescriptionreference_acquire(retVal);
|
||||
typelib_typedescription_release(pTD);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
throw BridgeRuntimeError(SAL_WHERE, "could not map given type name " + sTypeName);
|
||||
}
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|
58
bridges/source/net_uno/net_base.hxx
Normal file
58
bridges/source/net_uno/net_base.hxx
Normal file
|
@ -0,0 +1,58 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
||||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <rtl/ustring.hxx>
|
||||
#include <typelib/typedescription.hxx>
|
||||
#include <sal/log.hxx>
|
||||
|
||||
namespace net_uno
|
||||
{
|
||||
OUString map_uno_type_to_net(typelib_TypeDescriptionReference* pTDRef);
|
||||
typelib_TypeDescriptionReference* map_net_type_to_uno(const OUString& sTypeName);
|
||||
|
||||
struct BridgeRuntimeError
|
||||
{
|
||||
OUString m_location;
|
||||
OUString m_message;
|
||||
|
||||
explicit BridgeRuntimeError(const char* location, const OUString& message)
|
||||
: m_location(OUString::createFromAscii(location))
|
||||
, m_message(message)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class TypeDescHolder
|
||||
{
|
||||
public:
|
||||
TypeDescHolder(const TypeDescHolder&) = delete;
|
||||
TypeDescHolder& operator=(const TypeDescHolder&) = delete;
|
||||
|
||||
explicit TypeDescHolder(typelib_TypeDescriptionReference* td_ref)
|
||||
: m_td(nullptr)
|
||||
{
|
||||
TYPELIB_DANGER_GET(&m_td, td_ref);
|
||||
if (!m_td)
|
||||
{
|
||||
throw BridgeRuntimeError(SAL_WHERE, "could not get type description for "
|
||||
+ OUString::unacquired(&td_ref->pTypeName));
|
||||
}
|
||||
}
|
||||
~TypeDescHolder() { TYPELIB_DANGER_RELEASE(m_td); }
|
||||
|
||||
typelib_TypeDescription* get() const { return m_td; }
|
||||
|
||||
private:
|
||||
typelib_TypeDescription* m_td;
|
||||
};
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|
292
bridges/source/net_uno/net_bridge.cxx
Normal file
292
bridges/source/net_uno/net_bridge.cxx
Normal file
|
@ -0,0 +1,292 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
||||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "net_bridge.hxx"
|
||||
|
||||
#include <bridges/net_uno/net_context.hxx>
|
||||
#include <sal/log.hxx>
|
||||
|
||||
namespace net_uno
|
||||
{
|
||||
namespace
|
||||
{
|
||||
void SAL_CALL Mapping_acquire(uno_Mapping* mapping) SAL_THROW_EXTERN_C()
|
||||
{
|
||||
Mapping* that = static_cast<Mapping*>(mapping);
|
||||
that->m_bridge->acquire();
|
||||
}
|
||||
|
||||
void SAL_CALL Mapping_release(uno_Mapping* mapping) SAL_THROW_EXTERN_C()
|
||||
{
|
||||
Mapping* that = static_cast<Mapping*>(mapping);
|
||||
that->m_bridge->release();
|
||||
}
|
||||
|
||||
void SAL_CALL Mapping_free(uno_Mapping* mapping) SAL_THROW_EXTERN_C()
|
||||
{
|
||||
Mapping* that = static_cast<Mapping*>(mapping);
|
||||
delete that->m_bridge;
|
||||
}
|
||||
|
||||
void SAL_CALL Mapping_net2uno(uno_Mapping* mapping, void** ppOut, void* pIn,
|
||||
typelib_InterfaceTypeDescription* pTD) SAL_THROW_EXTERN_C()
|
||||
{
|
||||
assert(ppOut && pTD && "### null ptr!");
|
||||
|
||||
Mapping* that = static_cast<Mapping*>(mapping);
|
||||
Bridge* bridge = that->m_bridge;
|
||||
|
||||
if (pIn)
|
||||
{
|
||||
Value interfaceValue;
|
||||
interfaceValue.interfaceData = pIn;
|
||||
bridge->map_net_value_to_uno(*ppOut, &interfaceValue, pTD->aBase.pWeakRef, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
void SAL_CALL Mapping_uno2net(uno_Mapping* mapping, void** ppOut, void* pIn,
|
||||
typelib_InterfaceTypeDescription* pTD) SAL_THROW_EXTERN_C()
|
||||
{
|
||||
assert(ppOut && pTD && "### null ptr!");
|
||||
|
||||
Mapping* that = static_cast<Mapping*>(mapping);
|
||||
Bridge* bridge = that->m_bridge;
|
||||
|
||||
if (pIn)
|
||||
{
|
||||
Value interfaceValue;
|
||||
bridge->map_uno_to_net_value(&pIn, &interfaceValue, pTD->aBase.pWeakRef, false);
|
||||
*ppOut = interfaceValue.interfaceData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Bridge::Bridge(uno_Environment* uno_net_env, uno_ExtEnvironment* uno_env, bool registered_net2uno)
|
||||
: m_ref(1)
|
||||
, m_uno_env(uno_env)
|
||||
, m_net_env(uno_net_env)
|
||||
, m_registered_net2uno(registered_net2uno)
|
||||
{
|
||||
assert(m_net_env && m_uno_env);
|
||||
|
||||
(*m_uno_env->aBase.acquire)(&m_uno_env->aBase);
|
||||
(*m_net_env->acquire)(m_net_env);
|
||||
|
||||
// net2uno
|
||||
m_net2uno.acquire = Mapping_acquire;
|
||||
m_net2uno.release = Mapping_release;
|
||||
m_net2uno.mapInterface = Mapping_net2uno;
|
||||
m_net2uno.m_bridge = this;
|
||||
|
||||
// uno2net
|
||||
m_uno2net.acquire = Mapping_acquire;
|
||||
m_uno2net.release = Mapping_release;
|
||||
m_uno2net.mapInterface = Mapping_uno2net;
|
||||
m_uno2net.m_bridge = this;
|
||||
}
|
||||
|
||||
Bridge::~Bridge()
|
||||
{
|
||||
(*m_net_env->release)(m_net_env);
|
||||
(*m_uno_env->aBase.release)(&m_uno_env->aBase);
|
||||
}
|
||||
|
||||
void Bridge::acquire()
|
||||
{
|
||||
if (osl_atomic_increment(&m_ref) == 1)
|
||||
{
|
||||
if (m_registered_net2uno)
|
||||
{
|
||||
uno_Mapping* mapping = &m_net2uno;
|
||||
uno_registerMapping(&mapping, Mapping_free, m_net_env, &m_uno_env->aBase, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
uno_Mapping* mapping = &m_uno2net;
|
||||
uno_registerMapping(&mapping, Mapping_free, &m_uno_env->aBase, m_net_env, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Bridge::release()
|
||||
{
|
||||
if (osl_atomic_decrement(&m_ref) == 0)
|
||||
{
|
||||
uno_revokeMapping(m_registered_net2uno ? &m_net2uno : &m_uno2net);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
static void net_env_disposing(uno_Environment* env)
|
||||
{
|
||||
// TODO: more rigorous lifetime control
|
||||
// TODO: invoke some dispose routine on .NET side
|
||||
delete static_cast<Context*>(env->pContext);
|
||||
}
|
||||
|
||||
SAL_DLLPUBLIC_EXPORT void uno_initEnvironment(uno_Environment* net_env) SAL_THROW_EXTERN_C()
|
||||
{
|
||||
// The code creating the uno_Environment needs to initialize
|
||||
// pContext with a Context object, complete with all callbacks.
|
||||
assert(net_env->pContext);
|
||||
|
||||
net_env->pExtEnv = nullptr;
|
||||
net_env->environmentDisposing = net_env_disposing;
|
||||
}
|
||||
|
||||
SAL_DLLPUBLIC_EXPORT void uno_ext_getMapping(uno_Mapping** ppMapping, uno_Environment* pFrom,
|
||||
uno_Environment* pTo) SAL_THROW_EXTERN_C()
|
||||
{
|
||||
assert(ppMapping && pFrom && pTo);
|
||||
|
||||
if (*ppMapping)
|
||||
{
|
||||
(*(*ppMapping)->release)(*ppMapping);
|
||||
*ppMapping = nullptr;
|
||||
}
|
||||
|
||||
const OUString& from_env_typename = OUString::unacquired(&pFrom->pTypeName);
|
||||
const OUString& to_env_typename = OUString::unacquired(&pTo->pTypeName);
|
||||
|
||||
uno_Mapping* mapping = nullptr;
|
||||
if (from_env_typename == UNO_LB_NET && to_env_typename == UNO_LB_UNO)
|
||||
{
|
||||
Bridge* bridge = new Bridge(pFrom, pTo->pExtEnv, true);
|
||||
mapping = &bridge->m_net2uno;
|
||||
uno_registerMapping(&mapping, Mapping_free, pFrom, &pTo->pExtEnv->aBase, nullptr);
|
||||
}
|
||||
else if (from_env_typename == UNO_LB_UNO && to_env_typename == UNO_LB_NET)
|
||||
{
|
||||
Bridge* bridge = new Bridge(pTo, pFrom->pExtEnv, false);
|
||||
mapping = &bridge->m_uno2net;
|
||||
uno_registerMapping(&mapping, Mapping_free, &pFrom->pExtEnv->aBase, pTo, nullptr);
|
||||
}
|
||||
*ppMapping = mapping;
|
||||
}
|
||||
|
||||
SAL_DLLPUBLIC_EXPORT IntPtr allocateMemory(int nBytes) { return std::malloc(nBytes); }
|
||||
|
||||
SAL_DLLPUBLIC_EXPORT void freeMemory(IntPtr pMemory) { std::free(pMemory); }
|
||||
|
||||
SAL_DLLPUBLIC_EXPORT void releaseProxy(IntPtr pBridge, IntPtr pUnoInterface, IntPtr pTypeDesc)
|
||||
{
|
||||
Bridge* bridge = static_cast<Bridge*>(pBridge);
|
||||
uno_Interface* pUnoI = static_cast<uno_Interface*>(pUnoInterface);
|
||||
typelib_TypeDescription* pTD = static_cast<typelib_TypeDescription*>(pTypeDesc);
|
||||
|
||||
// Revoke from UNO; already revoked from .NET
|
||||
(*bridge->m_uno_env->revokeInterface)(bridge->m_uno_env, pUnoI);
|
||||
|
||||
(*pUnoI->release)(pUnoI);
|
||||
typelib_typedescription_release(pTD);
|
||||
bridge->release();
|
||||
}
|
||||
|
||||
SAL_DLLPUBLIC_EXPORT sal_Bool dispatchCall(IntPtr pBridge, IntPtr pUnoInterface, IntPtr pTypeDesc,
|
||||
String sFunctionName, Value* pArgs, Value* pRet,
|
||||
Value* pExc)
|
||||
{
|
||||
Bridge* bridge = static_cast<Bridge*>(pBridge);
|
||||
Context* context = static_cast<Context*>(bridge->m_net_env->pContext);
|
||||
|
||||
OUString sMethodName(sFunctionName);
|
||||
|
||||
try
|
||||
{
|
||||
uno_Interface* pUnoI = static_cast<uno_Interface*>(pUnoInterface);
|
||||
typelib_InterfaceTypeDescription* pTD
|
||||
= static_cast<typelib_InterfaceTypeDescription*>(pTypeDesc);
|
||||
|
||||
for (sal_Int32 i = 0; i < pTD->nAllMembers; ++i)
|
||||
{
|
||||
// Try to avoid getting typedescription as long as possible because
|
||||
// of Mutex.acquire() in typelib_typedescriptionreference_getDescription()
|
||||
typelib_TypeDescriptionReference* memberType = pTD->ppAllMembers[i];
|
||||
|
||||
// Check method_name against fully qualified typeName of memberType
|
||||
// typeName is of the form <name> "::" <method_name> *(":@" <idx> "," <idx> ":" <name>)
|
||||
const OUString& typeName = OUString::unacquired(&memberType->pTypeName);
|
||||
sal_Int32 offset = typeName.indexOf(':') + 2;
|
||||
sal_Int32 remainder = typeName.getLength() - offset;
|
||||
assert(offset >= 2 && offset < typeName.getLength() && typeName[offset - 1] == ':');
|
||||
|
||||
switch (memberType->eTypeClass)
|
||||
{
|
||||
case typelib_TypeClass_INTERFACE_METHOD:
|
||||
if ((sMethodName.getLength() == remainder
|
||||
|| (sMethodName.getLength() < remainder
|
||||
&& typeName[offset + sMethodName.getLength()] == ':'))
|
||||
&& typeName.match(sMethodName, offset))
|
||||
{
|
||||
TypeDescHolder memberTD(memberType);
|
||||
typelib_InterfaceMethodTypeDescription* pMethodTD
|
||||
= reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(
|
||||
memberTD.get());
|
||||
return bridge->call_uno_func(pUnoI, memberTD.get(),
|
||||
pMethodTD->pReturnTypeRef, pMethodTD->nParams,
|
||||
pMethodTD->pParams, pArgs, pRet, pExc);
|
||||
}
|
||||
break;
|
||||
|
||||
case typelib_TypeClass_INTERFACE_ATTRIBUTE:
|
||||
if (sMethodName.getLength() > 4
|
||||
&& (sMethodName.getLength() - 4 == remainder
|
||||
|| (sMethodName.getLength() - 4 < remainder
|
||||
&& typeName[offset + (sMethodName.getLength() - 4)] == ':'))
|
||||
&& sMethodName[1] == 'e' && sMethodName[2] == 't'
|
||||
&& rtl_ustr_compare_WithLength(
|
||||
typeName.getStr() + offset, sMethodName.getLength() - 4,
|
||||
sMethodName.getStr() + 4, sMethodName.getLength() - 4)
|
||||
== 0)
|
||||
{
|
||||
TypeDescHolder memberTD(memberType);
|
||||
typelib_InterfaceAttributeTypeDescription* pAttribTD
|
||||
= reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(
|
||||
memberTD.get());
|
||||
if (sMethodName[0] == 'g')
|
||||
{
|
||||
return bridge->call_uno_func(pUnoI, memberTD.get(),
|
||||
pAttribTD->pAttributeTypeRef, 0, nullptr,
|
||||
pArgs, pRet, pExc);
|
||||
}
|
||||
else if (sMethodName[0] == 's' && !pAttribTD->bReadOnly)
|
||||
{
|
||||
typelib_MethodParameter param;
|
||||
param.pTypeRef = pAttribTD->pAttributeTypeRef;
|
||||
param.bIn = true;
|
||||
param.bOut = false;
|
||||
|
||||
return bridge->call_uno_func(pUnoI, memberTD.get(),
|
||||
pAttribTD->pAttributeTypeRef, 1, ¶m,
|
||||
pArgs, pRet, pExc);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// No matching method info found
|
||||
throw BridgeRuntimeError(SAL_WHERE, "could not find function " + sMethodName
|
||||
+ " to call from type "
|
||||
+ OUString::unacquired(&pTD->aBase.pTypeName));
|
||||
}
|
||||
catch (const BridgeRuntimeError& err)
|
||||
{
|
||||
SAL_WARN("bridges", ".NET bridge error: " << err.m_message);
|
||||
context->throwError(err.m_location.getStr(), err.m_message.getStr());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|
59
bridges/source/net_uno/net_bridge.hxx
Normal file
59
bridges/source/net_uno/net_bridge.hxx
Normal file
|
@ -0,0 +1,59 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
||||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "net_base.hxx"
|
||||
|
||||
#include <bridges/net_uno/net_types.hxx>
|
||||
#include <uno/dispatcher.hxx>
|
||||
#include <uno/environment.hxx>
|
||||
#include <uno/mapping.hxx>
|
||||
|
||||
namespace net_uno
|
||||
{
|
||||
struct Bridge;
|
||||
|
||||
struct Mapping : public uno_Mapping
|
||||
{
|
||||
Bridge* m_bridge;
|
||||
};
|
||||
|
||||
struct Bridge
|
||||
{
|
||||
mutable oslInterlockedCount m_ref;
|
||||
uno_ExtEnvironment* m_uno_env;
|
||||
uno_Environment* m_net_env;
|
||||
|
||||
Mapping m_net2uno;
|
||||
Mapping m_uno2net;
|
||||
bool m_registered_net2uno;
|
||||
|
||||
Bridge(uno_Environment* net_env, uno_ExtEnvironment* uno_env, bool registered_net2uno);
|
||||
~Bridge();
|
||||
|
||||
void acquire();
|
||||
void release();
|
||||
|
||||
void map_uno_to_net_value(void* pUnoData, Value* pValue,
|
||||
typelib_TypeDescriptionReference* pTDRef, bool destructValue);
|
||||
void map_net_value_to_uno(void* pUnoData, Value* pValue,
|
||||
typelib_TypeDescriptionReference* pTDRef, bool destructObject,
|
||||
bool assignObject);
|
||||
|
||||
bool call_uno_func(uno_Interface* pUnoI, const typelib_TypeDescription* pMethodTD,
|
||||
typelib_TypeDescriptionReference* pReturnTDRef, int nParams,
|
||||
typelib_MethodParameter* pParams, Value* pArgs, Value* pRet, Value* pExc);
|
||||
void call_net_func(IntPtr pNetI, const typelib_TypeDescription* pMethodTD,
|
||||
typelib_TypeDescriptionReference* pReturnTDRef, int nParams,
|
||||
typelib_MethodParameter* pParams, void** pArgs, void* pRet, uno_Any** pExc);
|
||||
};
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|
855
bridges/source/net_uno/net_data.cxx
Normal file
855
bridges/source/net_uno/net_data.cxx
Normal file
|
@ -0,0 +1,855 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
||||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "net_bridge.hxx"
|
||||
#include "net_proxy.hxx"
|
||||
|
||||
#include <cstring>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <bridges/net_uno/net_context.hxx>
|
||||
|
||||
namespace net_uno
|
||||
{
|
||||
namespace
|
||||
{
|
||||
size_t net_sizeof(typelib_TypeClass eTypeClass)
|
||||
{
|
||||
static const std::unordered_map<typelib_TypeClass, size_t> s_sizes{
|
||||
{ typelib_TypeClass_BOOLEAN, sizeof(sal_Bool) },
|
||||
{ typelib_TypeClass_BYTE, sizeof(sal_Int8) },
|
||||
{ typelib_TypeClass_CHAR, sizeof(sal_Unicode) },
|
||||
{ typelib_TypeClass_SHORT, sizeof(sal_Int16) },
|
||||
{ typelib_TypeClass_UNSIGNED_SHORT, sizeof(sal_uInt16) },
|
||||
{ typelib_TypeClass_LONG, sizeof(sal_Int32) },
|
||||
{ typelib_TypeClass_UNSIGNED_LONG, sizeof(sal_uInt32) },
|
||||
{ typelib_TypeClass_HYPER, sizeof(sal_Int64) },
|
||||
{ typelib_TypeClass_UNSIGNED_HYPER, sizeof(sal_uInt64) },
|
||||
{ typelib_TypeClass_FLOAT, sizeof(float) },
|
||||
{ typelib_TypeClass_DOUBLE, sizeof(double) },
|
||||
{ typelib_TypeClass_ENUM, sizeof(sal_Int32) },
|
||||
{ typelib_TypeClass_STRING, sizeof(IntPtr) },
|
||||
{ typelib_TypeClass_TYPE, sizeof(IntPtr) },
|
||||
{ typelib_TypeClass_ANY, sizeof(IntPtr) + sizeof(IntPtr) },
|
||||
{ typelib_TypeClass_SEQUENCE, sizeof(IntPtr) + sizeof(sal_Int32) },
|
||||
{ typelib_TypeClass_INTERFACE, sizeof(IntPtr) },
|
||||
{ typelib_TypeClass_EXCEPTION, sizeof(IntPtr) },
|
||||
{ typelib_TypeClass_STRUCT, sizeof(IntPtr) },
|
||||
};
|
||||
return s_sizes.at(eTypeClass);
|
||||
}
|
||||
|
||||
IntPtr alloc_net_string(const OUString& str)
|
||||
{
|
||||
const sal_Unicode* src = str.getStr();
|
||||
sal_Int32 len = str.getLength();
|
||||
|
||||
void* dst = std::malloc((len + 1) * sizeof(sal_Unicode));
|
||||
std::memcpy(dst, src, len * sizeof(sal_Unicode));
|
||||
static_cast<sal_Unicode*>(dst)[len] = u'\0';
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
uno_Sequence* alloc_uno_sequence(sal_Int32 nElements, sal_Int32 nElementSize, void* data)
|
||||
{
|
||||
void* mem = std::malloc(SAL_SEQUENCE_HEADER_SIZE + nElements * nElementSize);
|
||||
|
||||
uno_Sequence* seq = static_cast<uno_Sequence*>(mem);
|
||||
seq->nRefCount = 1;
|
||||
seq->nElements = nElements;
|
||||
|
||||
if (data)
|
||||
std::memcpy(seq->elements, data, nElements * nElementSize);
|
||||
|
||||
return seq;
|
||||
}
|
||||
|
||||
void marshal_data(void* pUnoData, void* pNetData, typelib_TypeDescriptionReference* pTDRef,
|
||||
bool bDestructValue, Bridge& bridge)
|
||||
{
|
||||
switch (pTDRef->eTypeClass)
|
||||
{
|
||||
case typelib_TypeClass_BOOLEAN:
|
||||
case typelib_TypeClass_BYTE:
|
||||
case typelib_TypeClass_CHAR:
|
||||
case typelib_TypeClass_SHORT:
|
||||
case typelib_TypeClass_UNSIGNED_SHORT:
|
||||
case typelib_TypeClass_LONG:
|
||||
case typelib_TypeClass_UNSIGNED_LONG:
|
||||
case typelib_TypeClass_HYPER:
|
||||
case typelib_TypeClass_UNSIGNED_HYPER:
|
||||
case typelib_TypeClass_FLOAT:
|
||||
case typelib_TypeClass_DOUBLE:
|
||||
case typelib_TypeClass_ENUM:
|
||||
std::memcpy(pNetData, pUnoData, net_sizeof(pTDRef->eTypeClass));
|
||||
break;
|
||||
case typelib_TypeClass_STRING:
|
||||
{
|
||||
IntPtr* ppNetStr = static_cast<IntPtr*>(pNetData);
|
||||
rtl_uString* pUnoStr = *static_cast<rtl_uString**>(pUnoData);
|
||||
|
||||
if (bDestructValue && pNetData)
|
||||
std::free(pNetData);
|
||||
|
||||
*ppNetStr = alloc_net_string(OUString::unacquired(&pUnoStr));
|
||||
break;
|
||||
}
|
||||
case typelib_TypeClass_TYPE:
|
||||
{
|
||||
IntPtr* ppNetType = static_cast<IntPtr*>(pNetData);
|
||||
typelib_TypeDescriptionReference* pUnoType
|
||||
= *static_cast<typelib_TypeDescriptionReference**>(pUnoData);
|
||||
|
||||
if (bDestructValue && pNetData)
|
||||
std::free(pNetData);
|
||||
|
||||
*ppNetType = alloc_net_string(map_uno_type_to_net(pUnoType));
|
||||
break;
|
||||
}
|
||||
case typelib_TypeClass_ANY:
|
||||
{
|
||||
Value::Any* ppNetAny = static_cast<Value::Any*>(pNetData);
|
||||
uno_Any* pUnoAny = static_cast<uno_Any*>(pUnoData);
|
||||
|
||||
if (bDestructValue && ppNetAny->type)
|
||||
std::free(ppNetAny->type);
|
||||
if (bDestructValue && ppNetAny->data)
|
||||
std::free(ppNetAny->data);
|
||||
|
||||
ppNetAny->type = alloc_net_string(map_uno_type_to_net(pUnoAny->pType));
|
||||
|
||||
switch (pUnoAny->pType->eTypeClass)
|
||||
{
|
||||
case typelib_TypeClass_VOID:
|
||||
ppNetAny->data = nullptr;
|
||||
break;
|
||||
case typelib_TypeClass_BOOLEAN:
|
||||
case typelib_TypeClass_BYTE:
|
||||
case typelib_TypeClass_CHAR:
|
||||
case typelib_TypeClass_SHORT:
|
||||
case typelib_TypeClass_UNSIGNED_SHORT:
|
||||
case typelib_TypeClass_LONG:
|
||||
case typelib_TypeClass_UNSIGNED_LONG:
|
||||
case typelib_TypeClass_FLOAT:
|
||||
case typelib_TypeClass_ENUM:
|
||||
std::memcpy(&ppNetAny->data, pUnoAny->pData, sizeof(IntPtr));
|
||||
break;
|
||||
case typelib_TypeClass_HYPER:
|
||||
case typelib_TypeClass_UNSIGNED_HYPER:
|
||||
case typelib_TypeClass_DOUBLE:
|
||||
{
|
||||
size_t size = net_sizeof(pUnoAny->pType->eTypeClass);
|
||||
if (size <= sizeof(IntPtr))
|
||||
{
|
||||
std::memcpy(&ppNetAny->data, pUnoAny->pData, sizeof(IntPtr));
|
||||
}
|
||||
else
|
||||
{
|
||||
IntPtr mem = std::malloc(size);
|
||||
std::memcpy(mem, pUnoAny->pData, size);
|
||||
std::free(ppNetAny->data);
|
||||
ppNetAny->data = mem;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case typelib_TypeClass_ANY:
|
||||
case typelib_TypeClass_SEQUENCE:
|
||||
{
|
||||
IntPtr mem = std::malloc(net_sizeof(pUnoAny->pType->eTypeClass));
|
||||
marshal_data(pUnoAny->pData, mem, pUnoAny->pType, bDestructValue, bridge);
|
||||
std::free(ppNetAny->data);
|
||||
ppNetAny->data = mem;
|
||||
break;
|
||||
}
|
||||
case typelib_TypeClass_STRING:
|
||||
case typelib_TypeClass_TYPE:
|
||||
case typelib_TypeClass_INTERFACE:
|
||||
case typelib_TypeClass_EXCEPTION:
|
||||
case typelib_TypeClass_STRUCT:
|
||||
marshal_data(pUnoAny->pData, &ppNetAny->data, pUnoAny->pType, bDestructValue,
|
||||
bridge);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
throw BridgeRuntimeError(SAL_WHERE,
|
||||
"could not map "
|
||||
+ OUString::unacquired(&pUnoAny->pType->pTypeName)
|
||||
+ " out of an UNO any");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case typelib_TypeClass_SEQUENCE:
|
||||
{
|
||||
Value::Sequence* ppNetSeq = static_cast<Value::Sequence*>(pNetData);
|
||||
uno_Sequence* pUnoSeq = *static_cast<uno_Sequence**>(pUnoData);
|
||||
|
||||
if (bDestructValue && ppNetSeq->data)
|
||||
std::free(ppNetSeq->data);
|
||||
|
||||
ppNetSeq->length = pUnoSeq->nElements;
|
||||
|
||||
TypeDescHolder type(pTDRef);
|
||||
typelib_TypeDescriptionReference* pElemTDRef
|
||||
= reinterpret_cast<typelib_IndirectTypeDescription*>(type.get())->pType;
|
||||
|
||||
size_t nNetElemSize = net_sizeof(pElemTDRef->eTypeClass);
|
||||
|
||||
switch (pElemTDRef->eTypeClass)
|
||||
{
|
||||
case typelib_TypeClass_BOOLEAN:
|
||||
case typelib_TypeClass_BYTE:
|
||||
case typelib_TypeClass_CHAR:
|
||||
case typelib_TypeClass_SHORT:
|
||||
case typelib_TypeClass_UNSIGNED_SHORT:
|
||||
case typelib_TypeClass_LONG:
|
||||
case typelib_TypeClass_UNSIGNED_LONG:
|
||||
case typelib_TypeClass_HYPER:
|
||||
case typelib_TypeClass_UNSIGNED_HYPER:
|
||||
case typelib_TypeClass_FLOAT:
|
||||
case typelib_TypeClass_DOUBLE:
|
||||
case typelib_TypeClass_ENUM:
|
||||
{
|
||||
ppNetSeq->data = std::malloc(nNetElemSize * ppNetSeq->length);
|
||||
std::memcpy(ppNetSeq->data, pUnoSeq->elements, nNetElemSize * ppNetSeq->length);
|
||||
break;
|
||||
}
|
||||
case typelib_TypeClass_ANY:
|
||||
case typelib_TypeClass_SEQUENCE:
|
||||
case typelib_TypeClass_STRING:
|
||||
case typelib_TypeClass_TYPE:
|
||||
case typelib_TypeClass_INTERFACE:
|
||||
case typelib_TypeClass_EXCEPTION:
|
||||
case typelib_TypeClass_STRUCT:
|
||||
{
|
||||
TypeDescHolder elemType(pElemTDRef);
|
||||
sal_Int32 nUnoElemSize = elemType.get()->nSize;
|
||||
|
||||
ppNetSeq->data = std::malloc(nUnoElemSize * ppNetSeq->length);
|
||||
|
||||
// Convert each element
|
||||
for (int nPos = 0; nPos < ppNetSeq->length; ++nPos)
|
||||
{
|
||||
void* pNetElem = static_cast<char*>(ppNetSeq->data) + (nPos * nNetElemSize);
|
||||
void* pUnoElem = pUnoSeq->elements + (nPos * nUnoElemSize);
|
||||
marshal_data(pUnoElem, pNetElem, pElemTDRef, bDestructValue, bridge);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw BridgeRuntimeError(
|
||||
SAL_WHERE, "could not map " + OUString::unacquired(&pElemTDRef->pTypeName)
|
||||
+ " out of an UNO sequence");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case typelib_TypeClass_INTERFACE:
|
||||
{
|
||||
IntPtr* ppNetI = static_cast<IntPtr*>(pNetData);
|
||||
uno_Interface* pUnoI = *static_cast<uno_Interface**>(pUnoData);
|
||||
|
||||
if (pUnoI)
|
||||
{
|
||||
Context* pCtx = static_cast<Context*>(bridge.m_net_env->pContext);
|
||||
|
||||
// Get oid and type name
|
||||
rtl_uString* pOid = nullptr;
|
||||
(*bridge.m_uno_env->getObjectIdentifier)(bridge.m_uno_env, &pOid, pUnoI);
|
||||
const OUString& sOid = OUString::unacquired(&pOid);
|
||||
|
||||
OUString sTypeName = map_uno_type_to_net(pTDRef);
|
||||
|
||||
// Get the proxy if already created, else create new
|
||||
*ppNetI = pCtx->lookupInterface(sOid.getStr(), sTypeName.getStr());
|
||||
if (!*ppNetI)
|
||||
{
|
||||
TypeDescHolder type(pTDRef);
|
||||
typelib_InterfaceTypeDescription* pTD
|
||||
= reinterpret_cast<typelib_InterfaceTypeDescription*>(type.get());
|
||||
|
||||
// TODO: check whether liftime control is correct
|
||||
bridge.acquire();
|
||||
(*pUnoI->acquire)(pUnoI);
|
||||
typelib_typedescription_acquire(&pTD->aBase);
|
||||
(*bridge.m_uno_env->registerInterface)(
|
||||
bridge.m_uno_env, reinterpret_cast<void**>(&pUnoI), pOid, pTD);
|
||||
*ppNetI
|
||||
= pCtx->createProxy(sOid.getStr(), sTypeName.getStr(), &bridge, pUnoI, pTD);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppNetI = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case typelib_TypeClass_EXCEPTION:
|
||||
case typelib_TypeClass_STRUCT:
|
||||
{
|
||||
IntPtr* ppNetStruct = static_cast<IntPtr*>(pNetData);
|
||||
void* pUnoStruct = pUnoData;
|
||||
|
||||
if (bDestructValue && *ppNetStruct)
|
||||
std::free(*ppNetStruct);
|
||||
|
||||
TypeDescHolder type(pTDRef);
|
||||
typelib_CompoundTypeDescription* pCompTD
|
||||
= reinterpret_cast<typelib_CompoundTypeDescription*>(type.get());
|
||||
if (!type.get()->bComplete)
|
||||
typelib_typedescription_complete(
|
||||
reinterpret_cast<typelib_TypeDescription**>(&pCompTD));
|
||||
|
||||
size_t nBytes = 0;
|
||||
std::vector<std::pair<typelib_TypeDescriptionReference*, sal_Int32>> vecMembers;
|
||||
for (typelib_CompoundTypeDescription* pHierTD = pCompTD; pHierTD;
|
||||
pHierTD = pHierTD->pBaseTypeDescription)
|
||||
{
|
||||
for (int n = pHierTD->nMembers - 1; n >= 0; n--)
|
||||
{
|
||||
vecMembers.emplace_back(pHierTD->ppTypeRefs[n], pHierTD->pMemberOffsets[n]);
|
||||
nBytes += net_sizeof(pHierTD->ppTypeRefs[n]->eTypeClass);
|
||||
}
|
||||
}
|
||||
|
||||
*ppNetStruct = std::malloc(nBytes);
|
||||
|
||||
size_t nNetOffset = 0;
|
||||
int nPos = vecMembers.size() - 1;
|
||||
for (; nPos >= 0; nPos--)
|
||||
{
|
||||
auto[pMemberTDRef, nUnoOffset] = vecMembers[nPos];
|
||||
|
||||
void* pUnoField = static_cast<char*>(pUnoStruct) + nUnoOffset;
|
||||
void* pNetField = static_cast<char*>(*ppNetStruct) + nNetOffset;
|
||||
|
||||
switch (pMemberTDRef->eTypeClass)
|
||||
{
|
||||
case typelib_TypeClass_BOOLEAN:
|
||||
case typelib_TypeClass_BYTE:
|
||||
case typelib_TypeClass_CHAR:
|
||||
case typelib_TypeClass_SHORT:
|
||||
case typelib_TypeClass_UNSIGNED_SHORT:
|
||||
case typelib_TypeClass_LONG:
|
||||
case typelib_TypeClass_UNSIGNED_LONG:
|
||||
case typelib_TypeClass_HYPER:
|
||||
case typelib_TypeClass_UNSIGNED_HYPER:
|
||||
case typelib_TypeClass_FLOAT:
|
||||
case typelib_TypeClass_DOUBLE:
|
||||
case typelib_TypeClass_ENUM:
|
||||
std::memcpy(pNetField, pUnoField, net_sizeof(pMemberTDRef->eTypeClass));
|
||||
break;
|
||||
case typelib_TypeClass_ANY:
|
||||
case typelib_TypeClass_SEQUENCE:
|
||||
case typelib_TypeClass_STRING:
|
||||
case typelib_TypeClass_TYPE:
|
||||
case typelib_TypeClass_INTERFACE:
|
||||
case typelib_TypeClass_EXCEPTION:
|
||||
case typelib_TypeClass_STRUCT:
|
||||
marshal_data(pUnoField, pNetField, pMemberTDRef, bDestructValue, bridge);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
throw BridgeRuntimeError(
|
||||
SAL_WHERE,
|
||||
"could not map " + OUString::unacquired(&pMemberTDRef->pTypeName)
|
||||
+ " out of an UNO " + OUString::unacquired(&pTDRef->pTypeName));
|
||||
}
|
||||
}
|
||||
|
||||
nNetOffset += net_sizeof(pMemberTDRef->eTypeClass);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw BridgeRuntimeError(SAL_WHERE, "could not map "
|
||||
+ OUString::unacquired(&pTDRef->pTypeName)
|
||||
+ " value to .NET");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void unmarshal_data(void* pUnoData, void* pNetData, typelib_TypeDescriptionReference* pTDRef,
|
||||
bool bDestructObject, bool bAssignData, Bridge& bridge)
|
||||
{
|
||||
switch (pTDRef->eTypeClass)
|
||||
{
|
||||
case typelib_TypeClass_BOOLEAN:
|
||||
case typelib_TypeClass_BYTE:
|
||||
case typelib_TypeClass_CHAR:
|
||||
case typelib_TypeClass_SHORT:
|
||||
case typelib_TypeClass_UNSIGNED_SHORT:
|
||||
case typelib_TypeClass_LONG:
|
||||
case typelib_TypeClass_UNSIGNED_LONG:
|
||||
case typelib_TypeClass_HYPER:
|
||||
case typelib_TypeClass_UNSIGNED_HYPER:
|
||||
case typelib_TypeClass_FLOAT:
|
||||
case typelib_TypeClass_DOUBLE:
|
||||
case typelib_TypeClass_ENUM:
|
||||
if (bAssignData)
|
||||
std::memcpy(pUnoData, pNetData, net_sizeof(pTDRef->eTypeClass));
|
||||
break;
|
||||
case typelib_TypeClass_STRING:
|
||||
{
|
||||
rtl_uString** ppUnoStr = static_cast<rtl_uString**>(pUnoData);
|
||||
IntPtr pNetStr = *static_cast<IntPtr*>(pNetData);
|
||||
|
||||
if (bDestructObject && ppUnoStr)
|
||||
rtl_uString_release(*ppUnoStr);
|
||||
|
||||
if (bAssignData)
|
||||
{
|
||||
*ppUnoStr = nullptr;
|
||||
if (pNetStr)
|
||||
rtl_uString_newFromStr(ppUnoStr, static_cast<String>(pNetStr));
|
||||
else
|
||||
rtl_uString_new(ppUnoStr);
|
||||
}
|
||||
|
||||
std::free(pNetStr);
|
||||
break;
|
||||
}
|
||||
case typelib_TypeClass_TYPE:
|
||||
{
|
||||
typelib_TypeDescriptionReference** ppUnoType
|
||||
= static_cast<typelib_TypeDescriptionReference**>(pUnoData);
|
||||
IntPtr pNetType = *static_cast<IntPtr*>(pNetData);
|
||||
|
||||
if (bDestructObject && ppUnoType)
|
||||
typelib_typedescriptionreference_release(*ppUnoType);
|
||||
|
||||
if (bAssignData)
|
||||
*ppUnoType = map_net_type_to_uno(OUString(static_cast<String>(pNetType)));
|
||||
|
||||
std::free(pNetType);
|
||||
break;
|
||||
}
|
||||
case typelib_TypeClass_ANY:
|
||||
{
|
||||
uno_Any* pUnoAny = static_cast<uno_Any*>(pUnoData);
|
||||
Value::Any* pNetAny = static_cast<Value::Any*>(pNetData);
|
||||
|
||||
if (bDestructObject && pUnoData)
|
||||
uno_any_destruct(pUnoAny, nullptr);
|
||||
|
||||
typelib_TypeDescriptionReference* pValueTDRef
|
||||
= map_net_type_to_uno(OUString(static_cast<String>(pNetAny->type)));
|
||||
std::free(pNetAny->type);
|
||||
|
||||
if (bAssignData)
|
||||
{
|
||||
switch (pValueTDRef->eTypeClass)
|
||||
{
|
||||
case typelib_TypeClass_VOID:
|
||||
{
|
||||
pUnoAny->pType = pValueTDRef;
|
||||
pUnoAny->pData = &pUnoAny->pReserved;
|
||||
break;
|
||||
}
|
||||
case typelib_TypeClass_BOOLEAN:
|
||||
case typelib_TypeClass_BYTE:
|
||||
case typelib_TypeClass_CHAR:
|
||||
case typelib_TypeClass_SHORT:
|
||||
case typelib_TypeClass_UNSIGNED_SHORT:
|
||||
case typelib_TypeClass_LONG:
|
||||
case typelib_TypeClass_UNSIGNED_LONG:
|
||||
case typelib_TypeClass_FLOAT:
|
||||
case typelib_TypeClass_ENUM:
|
||||
{
|
||||
pUnoAny->pType = pValueTDRef;
|
||||
pUnoAny->pData = &pUnoAny->pReserved;
|
||||
std::memcpy(pUnoAny->pData, &pNetAny->data, sizeof(IntPtr));
|
||||
break;
|
||||
}
|
||||
case typelib_TypeClass_HYPER:
|
||||
case typelib_TypeClass_UNSIGNED_HYPER:
|
||||
case typelib_TypeClass_DOUBLE:
|
||||
{
|
||||
pUnoAny->pType = pValueTDRef;
|
||||
size_t size = net_sizeof(pValueTDRef->eTypeClass);
|
||||
if (size <= sizeof(IntPtr))
|
||||
{
|
||||
pUnoAny->pData = &pUnoAny->pReserved;
|
||||
std::memcpy(pUnoAny->pData, &pNetAny->data, sizeof(IntPtr));
|
||||
}
|
||||
else
|
||||
{
|
||||
void* mem = std::malloc(size);
|
||||
std::memcpy(mem, pNetAny->data, size);
|
||||
pUnoAny->pData = mem;
|
||||
std::free(pNetAny->data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case typelib_TypeClass_STRING:
|
||||
case typelib_TypeClass_TYPE:
|
||||
case typelib_TypeClass_INTERFACE:
|
||||
{
|
||||
if (pNetAny->data)
|
||||
{
|
||||
pUnoAny->pType = pValueTDRef;
|
||||
pUnoAny->pData = &pUnoAny->pReserved;
|
||||
pUnoAny->pReserved = nullptr;
|
||||
unmarshal_data(pUnoAny->pData, &pNetAny->data, pValueTDRef,
|
||||
bDestructObject, true, bridge);
|
||||
}
|
||||
else
|
||||
{
|
||||
uno_any_construct(pUnoAny, nullptr, nullptr, nullptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case typelib_TypeClass_ANY:
|
||||
case typelib_TypeClass_SEQUENCE:
|
||||
{
|
||||
if (pNetAny->data)
|
||||
{
|
||||
pUnoAny->pType = pValueTDRef;
|
||||
pUnoAny->pData = &pUnoAny->pReserved;
|
||||
pUnoAny->pReserved = nullptr;
|
||||
unmarshal_data(pUnoAny->pData, &pNetAny->data, pValueTDRef,
|
||||
bDestructObject, true, bridge);
|
||||
}
|
||||
else
|
||||
{
|
||||
uno_any_construct(pUnoAny, nullptr, nullptr, nullptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case typelib_TypeClass_STRUCT:
|
||||
case typelib_TypeClass_EXCEPTION:
|
||||
{
|
||||
if (pNetAny->data)
|
||||
{
|
||||
pUnoAny->pType = pValueTDRef;
|
||||
TypeDescHolder valueType(pValueTDRef);
|
||||
void* mem = std::malloc(valueType.get()->nSize);
|
||||
unmarshal_data(mem, &pNetAny->data, pValueTDRef, bDestructObject, true,
|
||||
bridge);
|
||||
pUnoAny->pData = mem;
|
||||
}
|
||||
else
|
||||
{
|
||||
uno_any_construct(pUnoAny, nullptr, nullptr, nullptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw BridgeRuntimeError(SAL_WHERE,
|
||||
"could not map "
|
||||
+ OUString::unacquired(&pValueTDRef->pTypeName)
|
||||
+ " into an UNO any");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (pValueTDRef->eTypeClass)
|
||||
{
|
||||
case typelib_TypeClass_VOID:
|
||||
case typelib_TypeClass_BOOLEAN:
|
||||
case typelib_TypeClass_BYTE:
|
||||
case typelib_TypeClass_CHAR:
|
||||
case typelib_TypeClass_SHORT:
|
||||
case typelib_TypeClass_UNSIGNED_SHORT:
|
||||
case typelib_TypeClass_LONG:
|
||||
case typelib_TypeClass_UNSIGNED_LONG:
|
||||
case typelib_TypeClass_FLOAT:
|
||||
case typelib_TypeClass_ENUM:
|
||||
break;
|
||||
case typelib_TypeClass_HYPER:
|
||||
case typelib_TypeClass_UNSIGNED_HYPER:
|
||||
case typelib_TypeClass_DOUBLE:
|
||||
{
|
||||
size_t size = net_sizeof(pValueTDRef->eTypeClass);
|
||||
if (pNetAny->data && size > sizeof(IntPtr))
|
||||
std::free(pNetAny->data);
|
||||
break;
|
||||
}
|
||||
case typelib_TypeClass_ANY:
|
||||
case typelib_TypeClass_SEQUENCE:
|
||||
{
|
||||
if (pNetAny->data)
|
||||
{
|
||||
unmarshal_data(pUnoAny->pData, &pNetAny->data, pValueTDRef,
|
||||
bDestructObject, false, bridge);
|
||||
std::free(pNetAny->data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case typelib_TypeClass_STRING:
|
||||
case typelib_TypeClass_TYPE:
|
||||
case typelib_TypeClass_INTERFACE:
|
||||
case typelib_TypeClass_STRUCT:
|
||||
case typelib_TypeClass_EXCEPTION:
|
||||
{
|
||||
if (pNetAny->data)
|
||||
{
|
||||
unmarshal_data(pUnoAny->pData, &pNetAny->data, pValueTDRef,
|
||||
bDestructObject, false, bridge);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw BridgeRuntimeError(SAL_WHERE,
|
||||
"could not map "
|
||||
+ OUString::unacquired(&pValueTDRef->pTypeName)
|
||||
+ " into an UNO any");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case typelib_TypeClass_SEQUENCE:
|
||||
{
|
||||
uno_Sequence** ppUnoSeq = static_cast<uno_Sequence**>(pUnoData);
|
||||
Value::Sequence* pNetSeq = static_cast<Value::Sequence*>(pNetData);
|
||||
|
||||
TypeDescHolder type(pTDRef);
|
||||
if (bDestructObject && ppUnoSeq)
|
||||
uno_destructData(ppUnoSeq, type.get(), nullptr);
|
||||
|
||||
typelib_TypeDescriptionReference* pElemTDRef
|
||||
= reinterpret_cast<typelib_IndirectTypeDescription*>(type.get())->pType;
|
||||
size_t nNetElemSize = net_sizeof(pElemTDRef->eTypeClass);
|
||||
|
||||
switch (pElemTDRef->eTypeClass)
|
||||
{
|
||||
case typelib_TypeClass_BOOLEAN:
|
||||
case typelib_TypeClass_BYTE:
|
||||
case typelib_TypeClass_CHAR:
|
||||
case typelib_TypeClass_SHORT:
|
||||
case typelib_TypeClass_UNSIGNED_SHORT:
|
||||
case typelib_TypeClass_LONG:
|
||||
case typelib_TypeClass_UNSIGNED_LONG:
|
||||
case typelib_TypeClass_HYPER:
|
||||
case typelib_TypeClass_UNSIGNED_HYPER:
|
||||
case typelib_TypeClass_FLOAT:
|
||||
case typelib_TypeClass_DOUBLE:
|
||||
case typelib_TypeClass_ENUM:
|
||||
if (bAssignData)
|
||||
*ppUnoSeq
|
||||
= alloc_uno_sequence(pNetSeq->length, nNetElemSize, pNetSeq->data);
|
||||
break;
|
||||
case typelib_TypeClass_ANY:
|
||||
case typelib_TypeClass_SEQUENCE:
|
||||
case typelib_TypeClass_STRING:
|
||||
case typelib_TypeClass_TYPE:
|
||||
case typelib_TypeClass_INTERFACE:
|
||||
case typelib_TypeClass_EXCEPTION:
|
||||
case typelib_TypeClass_STRUCT:
|
||||
{
|
||||
TypeDescHolder elemType(pElemTDRef);
|
||||
sal_Int32 nUnoElemSize = elemType.get()->nSize;
|
||||
|
||||
*ppUnoSeq = alloc_uno_sequence(pNetSeq->length, nUnoElemSize, nullptr);
|
||||
int nPos = 0;
|
||||
try
|
||||
{
|
||||
// Convert each element
|
||||
for (; nPos < pNetSeq->length; ++nPos)
|
||||
{
|
||||
void* pNetElem
|
||||
= static_cast<char*>(pNetSeq->data) + (nPos * nNetElemSize);
|
||||
void* pUnoElem = (*ppUnoSeq)->elements + (nPos * nUnoElemSize);
|
||||
unmarshal_data(pUnoElem, pNetElem, pElemTDRef, bDestructObject,
|
||||
bAssignData, bridge);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (bAssignData)
|
||||
{
|
||||
// Clean up already converted elements
|
||||
for (int nClean = 0; nClean < nPos; ++nClean)
|
||||
{
|
||||
void* pUnoElem = (*ppUnoSeq)->elements + (nClean * nUnoElemSize);
|
||||
uno_destructData(pUnoElem, elemType.get(), nullptr);
|
||||
}
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw BridgeRuntimeError(
|
||||
SAL_WHERE, "could not map " + OUString::unacquired(&pElemTDRef->pTypeName)
|
||||
+ " into an UNO sequence");
|
||||
}
|
||||
}
|
||||
|
||||
std::free(pNetSeq->data);
|
||||
break;
|
||||
}
|
||||
case typelib_TypeClass_INTERFACE:
|
||||
{
|
||||
uno_Interface** ppUnoI = static_cast<uno_Interface**>(pUnoData);
|
||||
IntPtr pNetI = *static_cast<IntPtr*>(pNetData);
|
||||
|
||||
TypeDescHolder type(pTDRef);
|
||||
if (bDestructObject && ppUnoI)
|
||||
uno_destructData(ppUnoI, type.get(), nullptr);
|
||||
|
||||
if (bAssignData)
|
||||
{
|
||||
if (pNetI)
|
||||
{
|
||||
Context* pCtx = static_cast<Context*>(bridge.m_net_env->pContext);
|
||||
|
||||
// Get oid and type description
|
||||
OUString sOid(pCtx->lookupObjectId(pNetI));
|
||||
|
||||
typelib_InterfaceTypeDescription* pInterfaceTD
|
||||
= reinterpret_cast<typelib_InterfaceTypeDescription*>(type.get());
|
||||
|
||||
// Get the proxy if already created, else create new
|
||||
*ppUnoI = nullptr;
|
||||
(*bridge.m_uno_env->getRegisteredInterface)(bridge.m_uno_env,
|
||||
reinterpret_cast<void**>(ppUnoI),
|
||||
sOid.pData, pInterfaceTD);
|
||||
|
||||
if (!*ppUnoI)
|
||||
*ppUnoI = new NetProxy(bridge, pNetI, pInterfaceTD, sOid);
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppUnoI = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case typelib_TypeClass_EXCEPTION:
|
||||
case typelib_TypeClass_STRUCT:
|
||||
{
|
||||
void* pUnoStruct = pUnoData;
|
||||
IntPtr pNetStruct = *static_cast<IntPtr*>(pNetData);
|
||||
|
||||
TypeDescHolder type(pTDRef);
|
||||
if (bDestructObject && pNetStruct)
|
||||
uno_destructData(pNetStruct, type.get(), nullptr);
|
||||
|
||||
typelib_CompoundTypeDescription* pCompTD
|
||||
= reinterpret_cast<typelib_CompoundTypeDescription*>(type.get());
|
||||
if (!type.get()->bComplete)
|
||||
typelib_typedescription_complete(
|
||||
reinterpret_cast<typelib_TypeDescription**>(&pCompTD));
|
||||
|
||||
std::vector<std::pair<typelib_TypeDescriptionReference*, sal_Int32>> vecMembers;
|
||||
for (typelib_CompoundTypeDescription* pHierTD = pCompTD; pHierTD;
|
||||
pHierTD = pHierTD->pBaseTypeDescription)
|
||||
{
|
||||
for (int n = pHierTD->nMembers - 1; n >= 0; n--)
|
||||
{
|
||||
vecMembers.emplace_back(pHierTD->ppTypeRefs[n], pHierTD->pMemberOffsets[n]);
|
||||
}
|
||||
}
|
||||
|
||||
size_t nNetOffset = 0;
|
||||
int nPos = vecMembers.size() - 1;
|
||||
try
|
||||
{
|
||||
for (; nPos >= 0; nPos--)
|
||||
{
|
||||
auto[pMemberTDRef, nUnoOffset] = vecMembers[nPos];
|
||||
|
||||
void* pUnoField = static_cast<char*>(pUnoStruct) + nUnoOffset;
|
||||
void* pNetField = static_cast<char*>(pNetStruct) + nNetOffset;
|
||||
|
||||
switch (pMemberTDRef->eTypeClass)
|
||||
{
|
||||
case typelib_TypeClass_BOOLEAN:
|
||||
case typelib_TypeClass_BYTE:
|
||||
case typelib_TypeClass_CHAR:
|
||||
case typelib_TypeClass_SHORT:
|
||||
case typelib_TypeClass_UNSIGNED_SHORT:
|
||||
case typelib_TypeClass_LONG:
|
||||
case typelib_TypeClass_UNSIGNED_LONG:
|
||||
case typelib_TypeClass_HYPER:
|
||||
case typelib_TypeClass_UNSIGNED_HYPER:
|
||||
case typelib_TypeClass_FLOAT:
|
||||
case typelib_TypeClass_DOUBLE:
|
||||
case typelib_TypeClass_ENUM:
|
||||
if (bAssignData)
|
||||
std::memcpy(pUnoField, pNetField,
|
||||
net_sizeof(pMemberTDRef->eTypeClass));
|
||||
break;
|
||||
case typelib_TypeClass_ANY:
|
||||
case typelib_TypeClass_SEQUENCE:
|
||||
case typelib_TypeClass_STRING:
|
||||
case typelib_TypeClass_TYPE:
|
||||
case typelib_TypeClass_INTERFACE:
|
||||
case typelib_TypeClass_EXCEPTION:
|
||||
case typelib_TypeClass_STRUCT:
|
||||
unmarshal_data(pUnoField, pNetField, pMemberTDRef, bDestructObject,
|
||||
bAssignData, bridge);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
throw BridgeRuntimeError(
|
||||
SAL_WHERE,
|
||||
"could not map " + OUString::unacquired(&pMemberTDRef->pTypeName)
|
||||
+ " into an UNO " + OUString::unacquired(&pTDRef->pTypeName));
|
||||
}
|
||||
}
|
||||
|
||||
nNetOffset += net_sizeof(pMemberTDRef->eTypeClass);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (bAssignData)
|
||||
{
|
||||
// Clean up already converted fields
|
||||
for (int nClean = vecMembers.size() - 1; nClean > nPos; nClean--)
|
||||
{
|
||||
auto[pMemberTDRef, nUnoOffset] = vecMembers[nClean];
|
||||
void* pUnoField = static_cast<char*>(pUnoStruct) + nUnoOffset;
|
||||
uno_type_destructData(pUnoField, pMemberTDRef, nullptr);
|
||||
}
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
std::free(pNetStruct);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw BridgeRuntimeError(SAL_WHERE, "could not map "
|
||||
+ OUString::unacquired(&pTDRef->pTypeName)
|
||||
+ " value to UNO");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Bridge::map_uno_to_net_value(void* pUnoData, Value* pValue,
|
||||
typelib_TypeDescriptionReference* pTDRef, bool bDestructValue)
|
||||
{
|
||||
marshal_data(pUnoData, pValue, pTDRef, bDestructValue, *this);
|
||||
}
|
||||
|
||||
void Bridge::map_net_value_to_uno(void* pUnoData, Value* pValue,
|
||||
typelib_TypeDescriptionReference* pTDRef, bool bDestructObject,
|
||||
bool bAssignObject)
|
||||
{
|
||||
unmarshal_data(pUnoData, pValue, pTDRef, bDestructObject, bAssignObject, *this);
|
||||
}
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|
251
bridges/source/net_uno/net_func.cxx
Normal file
251
bridges/source/net_uno/net_func.cxx
Normal file
|
@ -0,0 +1,251 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
||||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "net_bridge.hxx"
|
||||
|
||||
#include <bridges/net_uno/net_context.hxx>
|
||||
|
||||
namespace net_uno
|
||||
{
|
||||
void Bridge::call_net_func(IntPtr pNetI, const typelib_TypeDescription* pMethodTD,
|
||||
typelib_TypeDescriptionReference* pReturnTDRef, int nParams,
|
||||
typelib_MethodParameter* pParams, void** pArgs, void* pRet,
|
||||
uno_Any** pExc)
|
||||
{
|
||||
Value* pArgsRetExc = static_cast<Value*>(alloca((nParams + 2) * sizeof(Value)));
|
||||
|
||||
// Convert in and inout arguments
|
||||
for (int i = 0; i < nParams; ++i)
|
||||
{
|
||||
const typelib_MethodParameter& param = pParams[i];
|
||||
if (param.bIn)
|
||||
{
|
||||
map_uno_to_net_value(pArgs[i], &pArgsRetExc[i], param.pTypeRef, false);
|
||||
}
|
||||
}
|
||||
|
||||
OUString sMethodName = OUString::unacquired(&pMethodTD->pTypeName);
|
||||
Context* pCtx = static_cast<Context*>(m_net_env->pContext);
|
||||
bool error = !pCtx->dispatchCall(pNetI, sMethodName.getStr(), pArgsRetExc,
|
||||
&pArgsRetExc[nParams], &pArgsRetExc[nParams + 1]);
|
||||
|
||||
// Convert out and inout arguments
|
||||
for (int i = 0; i < nParams; ++i)
|
||||
{
|
||||
const typelib_MethodParameter& param = pParams[i];
|
||||
try
|
||||
{
|
||||
if (param.bOut)
|
||||
map_net_value_to_uno(pArgs[i], &pArgsRetExc[i], param.pTypeRef,
|
||||
param.bIn && param.bOut, true);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Clean up uno out args
|
||||
for (int n = 0; n < i; ++n)
|
||||
{
|
||||
const typelib_MethodParameter& param2 = pParams[n];
|
||||
if (param2.bOut)
|
||||
{
|
||||
uno_type_destructData(pArgs[n], param2.pTypeRef, nullptr);
|
||||
}
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
if (error)
|
||||
{
|
||||
map_net_value_to_uno(*pExc, &pArgsRetExc[nParams + 1],
|
||||
cppu::UnoType<css::uno::Any>::get().getTypeLibType(), false, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pReturnTDRef && pReturnTDRef->eTypeClass != typelib_TypeClass_VOID)
|
||||
{
|
||||
map_net_value_to_uno(pRet, &pArgsRetExc[nParams], pReturnTDRef, false, true);
|
||||
}
|
||||
|
||||
*pExc = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool Bridge::call_uno_func(uno_Interface* pUnoI, const typelib_TypeDescription* pMethodTD,
|
||||
typelib_TypeDescriptionReference* pReturnTDRef, int nParams,
|
||||
typelib_MethodParameter* pParams, Value* pArgs, Value* pRet, Value* pExc)
|
||||
{
|
||||
union largest {
|
||||
sal_Int64 n;
|
||||
double d;
|
||||
void* p;
|
||||
uno_Any a;
|
||||
};
|
||||
|
||||
// Calculate size of memory required for return value
|
||||
sal_Int32 nReturnSize = sizeof(largest);
|
||||
if (pReturnTDRef)
|
||||
{
|
||||
if (pReturnTDRef->eTypeClass == typelib_TypeClass_VOID)
|
||||
{
|
||||
nReturnSize = 0;
|
||||
}
|
||||
else if (pReturnTDRef->eTypeClass == typelib_TypeClass_STRUCT
|
||||
|| pReturnTDRef->eTypeClass == typelib_TypeClass_EXCEPTION)
|
||||
{
|
||||
TypeDescHolder returnTD(pReturnTDRef);
|
||||
if (o3tl::make_unsigned(returnTD.get()->nSize) > sizeof(largest))
|
||||
nReturnSize = returnTD.get()->nSize;
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare a memory block to contain all the converted arguments and return value
|
||||
//
|
||||
// The memory block contains pointers to small arguments stored in the same block.
|
||||
// If an argument is larger then `largest` union, such as a struct, then the pointer
|
||||
// points to an extra block of memory.
|
||||
//
|
||||
// The argument pointers are followed by the return value. If the return value is
|
||||
// larger than the `largest` union, this is a pointer to an extra block containing
|
||||
// the return value instead.
|
||||
//
|
||||
// For example: 2 arguments and return value
|
||||
// | Pointer 1 (void*)
|
||||
// | Pointer 2 (void*)
|
||||
// | Return Value (void*)
|
||||
// | Argument 1 (largest*)
|
||||
// | Argument 2 (largest*)
|
||||
|
||||
// Complete memory block
|
||||
char* mem = static_cast<char*>(
|
||||
alloca(nParams * sizeof(void*) + nReturnSize + nParams * sizeof(largest)));
|
||||
// Array of argument pointers; at the start of the memory block
|
||||
void** uno_args = reinterpret_cast<void**>(mem);
|
||||
// Pointer to return value memory; after all argument pointers
|
||||
void* uno_ret = nReturnSize == 0 ? nullptr : mem + nParams * sizeof(void*);
|
||||
// Space for actual arguments; after return value
|
||||
largest* uno_args_mem = reinterpret_cast<largest*>(mem + nParams * sizeof(void*) + nReturnSize);
|
||||
|
||||
for (sal_Int32 i = 0; i < nParams; ++i)
|
||||
{
|
||||
const typelib_MethodParameter& param = pParams[i];
|
||||
typelib_TypeDescriptionReference* type = param.pTypeRef;
|
||||
|
||||
uno_args[i] = &uno_args_mem[i];
|
||||
if (type->eTypeClass == typelib_TypeClass_STRUCT
|
||||
|| type->eTypeClass == typelib_TypeClass_EXCEPTION)
|
||||
{
|
||||
TypeDescHolder td(type);
|
||||
if (o3tl::make_unsigned(td.get()->nSize) > sizeof(largest))
|
||||
uno_args[i] = alloca(td.get()->nSize);
|
||||
}
|
||||
|
||||
if (param.bIn)
|
||||
{
|
||||
try
|
||||
{
|
||||
// in, in/out params
|
||||
map_net_value_to_uno(uno_args[i], &pArgs[i], type, false, true);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// cleanup uno in args
|
||||
for (sal_Int32 n = 0; n < i; ++n)
|
||||
{
|
||||
const typelib_MethodParameter& param2 = pParams[n];
|
||||
if (param2.bIn)
|
||||
{
|
||||
uno_type_destructData(uno_args[n], param2.pTypeRef, nullptr);
|
||||
}
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uno_Any uno_exc_holder;
|
||||
uno_Any* uno_exc = &uno_exc_holder;
|
||||
|
||||
// Propagate function call to binary uno
|
||||
(*pUnoI->pDispatcher)(pUnoI, pMethodTD, uno_ret, uno_args, &uno_exc);
|
||||
|
||||
if (!uno_exc)
|
||||
{
|
||||
// Convert out arguments and destruct previously converted uno args
|
||||
for (sal_Int32 i = 0; i < nParams; ++i)
|
||||
{
|
||||
const typelib_MethodParameter& param = pParams[i];
|
||||
typelib_TypeDescriptionReference* type = param.pTypeRef;
|
||||
|
||||
if (param.bOut)
|
||||
{
|
||||
try
|
||||
{
|
||||
map_uno_to_net_value(uno_args[i], &pArgs[i], param.pTypeRef, false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Cleanup rest of uno args
|
||||
for (sal_Int32 n = i; n < nParams; ++n)
|
||||
{
|
||||
uno_type_destructData(uno_args[n], pParams[n].pTypeRef, nullptr);
|
||||
}
|
||||
|
||||
// Cleanup uno return value
|
||||
uno_type_destructData(uno_ret, pReturnTDRef, nullptr);
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup args
|
||||
if (type->eTypeClass > typelib_TypeClass_DOUBLE
|
||||
&& type->eTypeClass != typelib_TypeClass_ENUM)
|
||||
{
|
||||
uno_type_destructData(uno_args[i], type, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (pReturnTDRef && pReturnTDRef->eTypeClass != typelib_TypeClass_VOID)
|
||||
{
|
||||
// Convert uno return value
|
||||
try
|
||||
{
|
||||
map_uno_to_net_value(uno_ret, pRet, pReturnTDRef, false);
|
||||
uno_type_destructData(uno_ret, pReturnTDRef, nullptr);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
uno_type_destructData(uno_ret, pReturnTDRef, nullptr);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else // An exception occurred
|
||||
{
|
||||
// Destruct uno in arguments
|
||||
for (sal_Int32 i = 0; i < nParams; ++i)
|
||||
{
|
||||
const typelib_MethodParameter& param = pParams[i];
|
||||
if (param.bIn)
|
||||
{
|
||||
uno_type_destructData(uno_args[i], param.pTypeRef, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
map_uno_to_net_value(uno_exc, pExc, cppu::UnoType<css::uno::Any>::get().getTypeLibType(),
|
||||
false);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|
175
bridges/source/net_uno/net_proxy.cxx
Normal file
175
bridges/source/net_uno/net_proxy.cxx
Normal file
|
@ -0,0 +1,175 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
||||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "net_proxy.hxx"
|
||||
#include "net_base.hxx"
|
||||
|
||||
#include <bridges/net_uno/net_context.hxx>
|
||||
|
||||
namespace net_uno
|
||||
{
|
||||
namespace
|
||||
{
|
||||
void SAL_CALL NetProxy_acquire(uno_Interface* pUnoI) SAL_THROW_EXTERN_C()
|
||||
{
|
||||
NetProxy* that = static_cast<NetProxy*>(pUnoI);
|
||||
that->acquire();
|
||||
}
|
||||
|
||||
void SAL_CALL NetProxy_release(uno_Interface* pUnoI) SAL_THROW_EXTERN_C()
|
||||
{
|
||||
NetProxy* that = static_cast<NetProxy*>(pUnoI);
|
||||
that->release();
|
||||
}
|
||||
|
||||
void SAL_CALL NetProxy_free([[maybe_unused]] uno_ExtEnvironment* pEnv, void* pUnoI)
|
||||
SAL_THROW_EXTERN_C()
|
||||
{
|
||||
NetProxy* that = static_cast<NetProxy*>(pUnoI);
|
||||
delete that;
|
||||
}
|
||||
|
||||
void SAL_CALL NetProxy_dispatch(uno_Interface* pUnoI, const typelib_TypeDescription* pMemberTD,
|
||||
void* pUnoRet, void** pUnoArgs, uno_Any** pUnoExc)
|
||||
SAL_THROW_EXTERN_C()
|
||||
{
|
||||
NetProxy* proxy = static_cast<NetProxy*>(pUnoI);
|
||||
|
||||
try
|
||||
{
|
||||
switch (pMemberTD->eTypeClass)
|
||||
{
|
||||
case typelib_TypeClass_INTERFACE_ATTRIBUTE:
|
||||
{
|
||||
const typelib_InterfaceAttributeTypeDescription* pAttribTD
|
||||
= reinterpret_cast<const typelib_InterfaceAttributeTypeDescription*>(pMemberTD);
|
||||
|
||||
if (pUnoRet) // getter
|
||||
{
|
||||
proxy->m_bridge.call_net_func(proxy->m_netI, pMemberTD,
|
||||
pAttribTD->pAttributeTypeRef, 0, nullptr, nullptr,
|
||||
pUnoRet, pUnoExc);
|
||||
}
|
||||
else // setter
|
||||
{
|
||||
typelib_MethodParameter param;
|
||||
param.pTypeRef = pAttribTD->pAttributeTypeRef;
|
||||
param.bIn = true;
|
||||
param.bOut = false;
|
||||
|
||||
proxy->m_bridge.call_net_func(proxy->m_netI, pMemberTD, nullptr, 1, ¶m,
|
||||
pUnoArgs, nullptr, pUnoExc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case typelib_TypeClass_INTERFACE_METHOD:
|
||||
{
|
||||
const typelib_InterfaceMethodTypeDescription* pMethodTD
|
||||
= reinterpret_cast<const typelib_InterfaceMethodTypeDescription*>(pMemberTD);
|
||||
|
||||
sal_Int32 nMemberPos = pMethodTD->aBase.nPosition;
|
||||
assert(nMemberPos < proxy->m_TD->nAllMembers);
|
||||
|
||||
sal_Int32 nFunctionPos = proxy->m_TD->pMapMemberIndexToFunctionIndex[nMemberPos];
|
||||
assert(nFunctionPos < proxy->m_TD->nMapFunctionIndexToMemberIndex);
|
||||
|
||||
switch (nFunctionPos)
|
||||
{
|
||||
case 1: // acquire()
|
||||
NetProxy_acquire(proxy);
|
||||
*pUnoExc = nullptr;
|
||||
break;
|
||||
case 2: // release()
|
||||
NetProxy_release(proxy);
|
||||
*pUnoExc = nullptr;
|
||||
break;
|
||||
default: // arbitrary method call
|
||||
proxy->m_bridge.call_net_func(
|
||||
proxy->m_netI, pMemberTD, pMethodTD->pReturnTypeRef, pMethodTD->nParams,
|
||||
pMethodTD->pParams, pUnoArgs, pUnoRet, pUnoExc);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw BridgeRuntimeError(SAL_WHERE,
|
||||
"could not find function "
|
||||
+ OUString::unacquired(&pMemberTD->pTypeName));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const BridgeRuntimeError& err)
|
||||
{
|
||||
SAL_WARN("bridges", ".NET bridge error: " << err.m_message);
|
||||
|
||||
css::uno::RuntimeException exc("[net_uno bridge error] " + err.m_message,
|
||||
css::uno::Reference<css::uno::XInterface>());
|
||||
uno_type_any_construct(*pUnoExc, &exc,
|
||||
cppu::UnoType<css::uno::RuntimeException>::get().getTypeLibType(),
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NetProxy::NetProxy(Bridge& rBridge, IntPtr pNetI, typelib_InterfaceTypeDescription* pTD,
|
||||
const OUString& sOid)
|
||||
: m_ref(1)
|
||||
, m_bridge(rBridge)
|
||||
, m_netI(nullptr)
|
||||
, m_oid(sOid)
|
||||
, m_TD(pTD)
|
||||
{
|
||||
void* that = this;
|
||||
(*m_bridge.m_uno_env->registerProxyInterface)(m_bridge.m_uno_env, &that, NetProxy_free,
|
||||
m_oid.pData, m_TD);
|
||||
|
||||
OUString sInterfaceName = map_uno_type_to_net(pTD->aBase.pWeakRef);
|
||||
|
||||
Context* pCtx = static_cast<Context*>(m_bridge.m_net_env->pContext);
|
||||
m_netI = pCtx->registerInterface(pNetI, m_oid.getStr(), sInterfaceName.getStr());
|
||||
|
||||
m_bridge.acquire();
|
||||
|
||||
uno_Interface::acquire = NetProxy_acquire;
|
||||
uno_Interface::release = NetProxy_release;
|
||||
uno_Interface::pDispatcher = NetProxy_dispatch;
|
||||
}
|
||||
|
||||
NetProxy::~NetProxy()
|
||||
{
|
||||
OUString sInterfaceName = map_uno_type_to_net(m_TD->aBase.pWeakRef);
|
||||
static_cast<Context*>(m_bridge.m_net_env->pContext)
|
||||
->revokeInterface(m_oid.getStr(), sInterfaceName.getStr());
|
||||
|
||||
m_bridge.release();
|
||||
}
|
||||
|
||||
void NetProxy::acquire()
|
||||
{
|
||||
// rebirth of proxy zombie
|
||||
if (osl_atomic_increment(&m_ref) == 1)
|
||||
{
|
||||
void* that = this;
|
||||
(*m_bridge.m_uno_env->registerProxyInterface)(m_bridge.m_uno_env, &that, NetProxy_free,
|
||||
m_oid.pData, m_TD);
|
||||
}
|
||||
}
|
||||
|
||||
void NetProxy::release()
|
||||
{
|
||||
// revoke from uno env on last release
|
||||
if (osl_atomic_decrement(&m_ref) == 0)
|
||||
{
|
||||
(*m_bridge.m_uno_env->revokeInterface)(m_bridge.m_uno_env, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|
36
bridges/source/net_uno/net_proxy.hxx
Normal file
36
bridges/source/net_uno/net_proxy.hxx
Normal file
|
@ -0,0 +1,36 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
||||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "net_bridge.hxx"
|
||||
|
||||
#include <bridges/net_uno/net_types.hxx>
|
||||
#include <rtl/ustring.hxx>
|
||||
|
||||
namespace net_uno
|
||||
{
|
||||
struct NetProxy : public uno_Interface
|
||||
{
|
||||
mutable oslInterlockedCount m_ref;
|
||||
Bridge& m_bridge;
|
||||
IntPtr m_netI;
|
||||
OUString m_oid;
|
||||
typelib_InterfaceTypeDescription* m_TD;
|
||||
|
||||
NetProxy(Bridge& rBridge, IntPtr pNetI, typelib_InterfaceTypeDescription* pTD,
|
||||
const OUString& sOid);
|
||||
~NetProxy();
|
||||
|
||||
void acquire();
|
||||
void release();
|
||||
};
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|
|
@ -377,6 +377,30 @@ void NetProducer::producePlainStruct(std::string_view name,
|
|||
file.endBlock();
|
||||
file.endLine(); // extra blank line
|
||||
|
||||
// generate deconstructor
|
||||
file.beginLine().append("public void Deconstruct(");
|
||||
separatedForeach(allFields, [&file]() { file.append(", "); },
|
||||
[this, &file](const auto& member) {
|
||||
file.append("out ")
|
||||
.append(getNetName(member.type))
|
||||
.append(" ")
|
||||
.append(getSafeIdentifier(member.name));
|
||||
});
|
||||
file.append(")").endLine();
|
||||
file.beginBlock();
|
||||
for (const auto& member : allFields)
|
||||
{
|
||||
file.beginLine()
|
||||
.append(getSafeIdentifier(member.name))
|
||||
.append(" = ")
|
||||
.append("this.")
|
||||
.append(getSafeIdentifier(member.name))
|
||||
.append(";")
|
||||
.endLine();
|
||||
}
|
||||
file.endBlock();
|
||||
file.endLine(); // extra blank line
|
||||
|
||||
// generate struct fields
|
||||
for (const auto& member : entity->getDirectMembers())
|
||||
{
|
||||
|
@ -586,6 +610,30 @@ void NetProducer::produceException(std::string_view name,
|
|||
file.endBlock();
|
||||
file.endLine(); // extra blank line
|
||||
|
||||
// generate deconstructor
|
||||
file.beginLine().append("public void Deconstruct(");
|
||||
separatedForeach(allFields, [&file]() { file.append(", "); },
|
||||
[this, &file](const auto& member) {
|
||||
file.append("out ")
|
||||
.append(getNetName(member.type))
|
||||
.append(" ")
|
||||
.append(getSafeIdentifier(member.name));
|
||||
});
|
||||
file.append(")").endLine();
|
||||
file.beginBlock();
|
||||
for (const auto& member : allFields)
|
||||
{
|
||||
file.beginLine()
|
||||
.append(getSafeIdentifier(member.name))
|
||||
.append(" = ")
|
||||
.append("this.")
|
||||
.append(getSafeIdentifier(member.name))
|
||||
.append(";")
|
||||
.endLine();
|
||||
}
|
||||
file.endBlock();
|
||||
file.endLine(); // extra blank line
|
||||
|
||||
// generate exception fields
|
||||
for (const auto& member : entity->getDirectMembers())
|
||||
{
|
||||
|
@ -918,15 +966,16 @@ void NetProducer::produceService(
|
|||
.append("ctx.getServiceManager();")
|
||||
.endLine()
|
||||
.beginLine()
|
||||
.append(returnType)
|
||||
.append(" srv = (")
|
||||
.append(returnType)
|
||||
.append(")mcf.createInstanceWithContext(\"")
|
||||
.append("com.sun.star.uno.Any srv = new com.sun.star.uno.Any(")
|
||||
.append("mcf.createInstanceWithContext(\"")
|
||||
.append(name)
|
||||
.append("\", ctx);")
|
||||
.append("\", ctx));")
|
||||
.endLine()
|
||||
.beginLine()
|
||||
.append("return srv;")
|
||||
.append("return srv.cast<")
|
||||
.append(returnType)
|
||||
.append(">();")
|
||||
.beginLine()
|
||||
.endLine()
|
||||
.endBlock();
|
||||
|
||||
|
@ -949,8 +998,8 @@ void NetProducer::produceService(
|
|||
.endLine()
|
||||
.beginBlock()
|
||||
.beginLine()
|
||||
.append(
|
||||
"throw new com.sun.star.uno.DeploymentException(\"Could not create service ")
|
||||
.append("throw new com.sun.star.uno.DeploymentException(")
|
||||
.append("\"Could not create service ")
|
||||
.append(name)
|
||||
.append(" from given XComponentContext\", ctx);")
|
||||
.endLine()
|
||||
|
@ -989,10 +1038,8 @@ void NetProducer::produceService(
|
|||
.append("ctx.getServiceManager();")
|
||||
.endLine()
|
||||
.beginLine()
|
||||
.append(returnType)
|
||||
.append(" srv = (")
|
||||
.append(returnType)
|
||||
.append(")mcf.createInstanceWithArgumentsAndContext(\"")
|
||||
.append("com.sun.star.uno.Any srv = new com.sun.star.uno.Any(")
|
||||
.append("mcf.createInstanceWithArgumentsAndContext(\"")
|
||||
.append(name)
|
||||
.append("\", ");
|
||||
if (restParam)
|
||||
|
@ -1014,7 +1061,14 @@ void NetProducer::produceService(
|
|||
});
|
||||
file.append(" }");
|
||||
}
|
||||
file.append(", ctx);").endLine().beginLine().append("return srv;").endLine().endBlock();
|
||||
file.append(", ctx));")
|
||||
.endLine()
|
||||
.beginLine()
|
||||
.append("return srv.cast<")
|
||||
.append(returnType)
|
||||
.append(">();")
|
||||
.endLine()
|
||||
.endBlock();
|
||||
|
||||
for (const auto& e : ctor.exceptions)
|
||||
{
|
||||
|
@ -1035,8 +1089,8 @@ void NetProducer::produceService(
|
|||
.endLine()
|
||||
.beginBlock()
|
||||
.beginLine()
|
||||
.append(
|
||||
"throw new com.sun.star.uno.DeploymentException(\"Could not create service ")
|
||||
.append("throw new com.sun.star.uno.DeploymentException(")
|
||||
.append("\"Could not create service ")
|
||||
.append(name)
|
||||
.append(" from given XComponentContext\", ctx);")
|
||||
.endLine()
|
||||
|
@ -1089,12 +1143,23 @@ void NetProducer::produceSingleton(
|
|||
.beginBlock();
|
||||
|
||||
file.beginLine()
|
||||
.append("try")
|
||||
.endLine()
|
||||
.beginBlock()
|
||||
.beginLine()
|
||||
.append("com.sun.star.uno.Any sgtn = ctx.getValueByName(\"/singletons/")
|
||||
.append(name)
|
||||
.append("\");")
|
||||
.endLine();
|
||||
.endLine()
|
||||
.beginLine()
|
||||
.append("return sgtn.cast<")
|
||||
.append(getNetName(entity->getBase()))
|
||||
.append(">();")
|
||||
.endLine()
|
||||
.endBlock();
|
||||
|
||||
file.beginLine()
|
||||
.append("if (!sgtn.hasValue())")
|
||||
.append("catch")
|
||||
.endLine()
|
||||
.beginBlock()
|
||||
.beginLine()
|
||||
|
@ -1103,11 +1168,6 @@ void NetProducer::produceSingleton(
|
|||
.append(" from given XComponentContext\", ctx);")
|
||||
.endLine()
|
||||
.endBlock();
|
||||
file.beginLine()
|
||||
.append("return (")
|
||||
.append(getNetName(entity->getBase()))
|
||||
.append(")sgtn.Value;")
|
||||
.endLine();
|
||||
|
||||
file.endBlock().endBlock();
|
||||
|
||||
|
|
38
include/bridges/net_uno/net_context.hxx
Normal file
38
include/bridges/net_uno/net_context.hxx
Normal file
|
@ -0,0 +1,38 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
||||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <bridges/net_uno/net_types.hxx>
|
||||
|
||||
namespace net_uno
|
||||
{
|
||||
typedef IntPtr (*CreateProxyFunc)(String pOid, String pInterfaceName, IntPtr pBridge,
|
||||
IntPtr pUnoInterface, IntPtr pTD);
|
||||
typedef String (*LookupObjectIdFunc)(IntPtr pNetInterface);
|
||||
typedef IntPtr (*RegisterInterfaceFunc)(IntPtr pNetInterface, String pOid, String pInterfaceName);
|
||||
typedef IntPtr (*LookupInterfaceFunc)(String pOid, String pInterfaceName);
|
||||
typedef void (*RevokeInterfaceFunc)(String pOid, String pInterfaceName);
|
||||
typedef sal_Int8 (*DispatchCallFunc)(IntPtr pNetInterface, String pMethodName, Value* pArgs,
|
||||
Value* pRet, Value* pExc);
|
||||
typedef void (*ThrowErrorFunc)(String pWhere, String pMessage);
|
||||
|
||||
struct Context
|
||||
{
|
||||
CreateProxyFunc createProxy;
|
||||
LookupObjectIdFunc lookupObjectId;
|
||||
RegisterInterfaceFunc registerInterface;
|
||||
LookupInterfaceFunc lookupInterface;
|
||||
RevokeInterfaceFunc revokeInterface;
|
||||
DispatchCallFunc dispatchCall;
|
||||
ThrowErrorFunc throwError;
|
||||
};
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|
79
include/bridges/net_uno/net_types.hxx
Normal file
79
include/bridges/net_uno/net_types.hxx
Normal file
|
@ -0,0 +1,79 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
||||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sal/types.h>
|
||||
|
||||
namespace net_uno
|
||||
{
|
||||
using IntPtr = void*;
|
||||
using String = const sal_Unicode*;
|
||||
|
||||
union Value {
|
||||
// bool
|
||||
sal_Bool boolData;
|
||||
|
||||
// byte
|
||||
sal_Int8 byteData;
|
||||
|
||||
// char
|
||||
sal_Unicode charData;
|
||||
|
||||
// short
|
||||
sal_Int16 shortData;
|
||||
sal_uInt16 unsigShortData;
|
||||
|
||||
// long
|
||||
sal_Int32 longData;
|
||||
sal_uInt32 unsigLongData;
|
||||
|
||||
// hyper
|
||||
sal_Int64 hyperData;
|
||||
sal_uInt64 unsigHyperData;
|
||||
|
||||
// float/double
|
||||
float floatData;
|
||||
double doubleData;
|
||||
|
||||
// string
|
||||
IntPtr stringData;
|
||||
|
||||
// type
|
||||
IntPtr typeData;
|
||||
|
||||
// any
|
||||
struct Any
|
||||
{
|
||||
IntPtr data;
|
||||
IntPtr type;
|
||||
} anyData;
|
||||
|
||||
// enum
|
||||
sal_Int32 enumData;
|
||||
|
||||
// struct
|
||||
IntPtr structData;
|
||||
|
||||
// exception
|
||||
IntPtr exceptionData;
|
||||
|
||||
// sequence
|
||||
struct Sequence
|
||||
{
|
||||
IntPtr data;
|
||||
sal_Int32 length;
|
||||
} sequenceData;
|
||||
|
||||
// interface
|
||||
IntPtr interfaceData;
|
||||
};
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|
|
@ -641,6 +641,7 @@ certain functionality.
|
|||
@li @c lingucomponent
|
||||
@li @c linguistic
|
||||
@li @c lwp - lotuswordpro
|
||||
@li @c net
|
||||
@li @c opencl
|
||||
@li @c opencl.device
|
||||
@li @c opencl.file
|
||||
|
|
|
@ -51,6 +51,8 @@ provoking error here, because PP ignores #error
|
|||
#define UNO_LB_JAVA "java"
|
||||
/** Environment type name for CLI (Common Language Infrastructure). */
|
||||
#define UNO_LB_CLI "cli"
|
||||
/** Environment type name for new .NET Bindings. */
|
||||
#define UNO_LB_NET "net"
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -9,13 +9,33 @@
|
|||
$(eval $(call gb_DotnetLibrary_DotnetLibrary,net_bridge,$(gb_DotnetLibrary_CS)))
|
||||
|
||||
$(eval $(call gb_DotnetLibrary_add_sources,net_bridge,\
|
||||
net_ure/source/bridge/NativeBootstrap \
|
||||
net_ure/source/bridge/helper/DisposeGuard \
|
||||
net_ure/source/bridge/helper/StructHelper \
|
||||
net_ure/source/bridge/helper/TypeHelper \
|
||||
net_ure/source/bridge/helper/WeakBase \
|
||||
net_ure/source/bridge/helper/WeakComponentBase \
|
||||
))
|
||||
|
||||
$(eval $(call gb_DotnetLibrary_add_sources,net_bridge,\
|
||||
net_ure/source/bridge/native/InteropMethods \
|
||||
net_ure/source/bridge/native/InteropTypes \
|
||||
net_ure/source/bridge/native/Marshaller \
|
||||
net_ure/source/bridge/native/NativeBootstrap \
|
||||
net_ure/source/bridge/native/NativeUnoProxy \
|
||||
net_ure/source/bridge/native/NetEnvironment \
|
||||
net_ure/source/bridge/native/WeakIndexTable \
|
||||
net_ure/source/bridge/native/WeakOidTypeTable \
|
||||
))
|
||||
|
||||
$(eval $(call gb_DotnetLibrary_add_properties,net_bridge,\
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> \
|
||||
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles> \
|
||||
))
|
||||
|
||||
$(eval $(call gb_DotnetLibrary_add_items,net_bridge,\
|
||||
<PackageReference Include="System.Reflection.DispatchProxy" Version="4.7.1" /> \
|
||||
))
|
||||
|
||||
$(eval $(call gb_DotnetLibrary_link_library,net_bridge,net_uretypes))
|
||||
|
||||
$(eval $(call gb_DotnetLibrary_add_properties,net_bridge,\
|
||||
|
|
|
@ -28,7 +28,6 @@ public class AnyTests
|
|||
public void with_RejectsInvalidParams()
|
||||
{
|
||||
Assert.That(() => Any.with<Any>(Any.VOID), Throws.ArgumentException);
|
||||
Assert.That(() => Any.with<int>(null), Throws.ArgumentException);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
|
|
@ -17,9 +17,51 @@ namespace com.sun.star.uno
|
|||
public Type Type { get; private set; }
|
||||
public Object Value { get; private set; }
|
||||
|
||||
public Any(object value) => setValue(value?.GetType() ?? typeof(void), value);
|
||||
public Any(Type type, object value) => setValue(type, value);
|
||||
public Any(object value) : this(value?.GetType() ?? typeof(void), value) { }
|
||||
public static Any with<T>(object value) => new Any(typeof(T), value);
|
||||
public static Any with<T>(T value) => new Any(typeof(T), value);
|
||||
|
||||
public bool contains<T>()
|
||||
{
|
||||
if (typeof(IQueryInterface).IsAssignableFrom(Type))
|
||||
{
|
||||
if (typeof(T).IsAssignableFrom(Type))
|
||||
// Special case for already implemented interface
|
||||
return true;
|
||||
else if (typeof(IQueryInterface).IsAssignableFrom(typeof(T)))
|
||||
// Special case for contained IQueryInterface
|
||||
return ((IQueryInterface)Value).queryInterface(typeof(T)).hasValue();
|
||||
}
|
||||
return typeof(T).IsAssignableFrom(Type);
|
||||
}
|
||||
|
||||
public T cast<T>()
|
||||
{
|
||||
if (typeof(IQueryInterface).IsAssignableFrom(Type))
|
||||
{
|
||||
if (typeof(T).IsAssignableFrom(Type))
|
||||
// Special case for already implemented interface
|
||||
return (T)Value;
|
||||
else if (typeof(IQueryInterface).IsAssignableFrom(typeof(T)))
|
||||
// Special case for contained IQueryInterface
|
||||
return (T)((IQueryInterface)Value).queryInterface(typeof(T)).Value;
|
||||
}
|
||||
return (T)Value;
|
||||
}
|
||||
|
||||
public T castOrDefault<T>(T fallback = default)
|
||||
{
|
||||
if (typeof(IQueryInterface).IsAssignableFrom(Type))
|
||||
{
|
||||
if (typeof(T).IsAssignableFrom(Type))
|
||||
// Special case for already implemented interface
|
||||
return (T)Value;
|
||||
else if (typeof(IQueryInterface).IsAssignableFrom(typeof(T)))
|
||||
// Special case for contained IQueryInterface
|
||||
return (T)((IQueryInterface)Value).queryInterface(typeof(T)).Value;
|
||||
}
|
||||
return typeof(T).IsAssignableFrom(Type) ? (T)Value : fallback;
|
||||
}
|
||||
|
||||
public bool hasValue() => Type != typeof(void);
|
||||
|
||||
|
@ -53,6 +95,6 @@ namespace com.sun.star.uno
|
|||
public override bool Equals(object obj) => obj is Any other && equals(other);
|
||||
public override int GetHashCode() => (Type, Value).GetHashCode();
|
||||
|
||||
public override string ToString() => $"uno.Any {{ Type = {Type}, Value = {Value ?? "Null"} }}";
|
||||
public override string ToString() => $"com.sun.star.uno.Any {{ Type = {Type}, Value = {Value ?? "Null"} }}";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,26 @@ namespace com.sun.star.uno
|
|||
{
|
||||
public interface IQueryInterface
|
||||
{
|
||||
// Kept empty for now, until the .NET bridge is in place
|
||||
Any queryInterface(Type type);
|
||||
}
|
||||
|
||||
public static class IQueryInterfaceExtensions
|
||||
{
|
||||
public static bool implements<T>(this IQueryInterface iqi)
|
||||
where T : IQueryInterface
|
||||
=> iqi is T ? true : iqi.queryInterface(typeof(T)).hasValue();
|
||||
|
||||
public static T query<T>(this IQueryInterface iqi)
|
||||
where T : IQueryInterface
|
||||
=> iqi is T t ? t : (T)iqi.queryInterface(typeof(T)).Value;
|
||||
|
||||
public static T queryOrDefault<T>(this IQueryInterface iqi, T fallback = default)
|
||||
where T : IQueryInterface
|
||||
{
|
||||
if (iqi is T t)
|
||||
return t;
|
||||
Any result = iqi.queryInterface(typeof(T));
|
||||
return result.hasValue() ? (T)result.Value : fallback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,41 +9,113 @@
|
|||
|
||||
#include <string_view>
|
||||
|
||||
#include <bridges/net_uno/net_context.hxx>
|
||||
#include <cppuhelper/bootstrap.hxx>
|
||||
#include <o3tl/string_view.hxx>
|
||||
#include <rtl/bootstrap.hxx>
|
||||
#include <rtl/ustring.hxx>
|
||||
#include <sal/log.hxx>
|
||||
#include <uno/mapping.hxx>
|
||||
|
||||
#include <com/sun/star/lang/XComponent.hpp>
|
||||
#include <com/sun/star/uno/XComponentContext.hpp>
|
||||
|
||||
using namespace ::com::sun::star;
|
||||
using namespace ::com::sun::star::uno;
|
||||
|
||||
namespace net_uno
|
||||
{
|
||||
extern "C" {
|
||||
|
||||
SAL_DLLPUBLIC_EXPORT void* bootstrap(const sal_Unicode* sParams)
|
||||
SAL_DLLPUBLIC_EXPORT IntPtr bootstrap(const Context aContext)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Bootstrap UNO and start a LibreOffice process if needed
|
||||
Reference<XComponentContext> xContext(::cppu::bootstrap());
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
SAL_DLLPUBLIC_EXPORT IntPtr defaultBootstrap_InitialComponentContext(const sal_Unicode* sIniFile,
|
||||
const sal_Unicode* sParams,
|
||||
const Context aContext)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Set bootstrap parameters, merged into a single string (at least for now)
|
||||
// to avoid dealing with lifetimes and memory of multiple strings
|
||||
if (sParams)
|
||||
{
|
||||
OUString paramsStr(sParams);
|
||||
for (size_t i = 0; i != std::u16string_view::npos;)
|
||||
{
|
||||
std::u16string_view name(o3tl::getToken(paramsStr, u'=', i));
|
||||
OUString key(name.substr(0, name.find_first_of('|')));
|
||||
std::u16string_view name(o3tl::getToken(paramsStr, u'|', i));
|
||||
OUString key(name.substr(0, name.find_first_of('=')));
|
||||
OUString val(name.substr(key.getLength() + 1));
|
||||
::rtl::Bootstrap::set(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
Reference<XComponentContext> xContext(::cppu::bootstrap());
|
||||
return xContext.get();
|
||||
// Bootstrap UNO
|
||||
Reference<XComponentContext> xContext;
|
||||
if (sIniFile)
|
||||
{
|
||||
xContext = ::cppu::defaultBootstrap_InitialComponentContext(OUString(sIniFile));
|
||||
}
|
||||
else
|
||||
{
|
||||
xContext = ::cppu::defaultBootstrap_InitialComponentContext();
|
||||
}
|
||||
|
||||
// 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 (...)
|
||||
catch (const Exception& exc)
|
||||
{
|
||||
SAL_WARN("net", ".NET bootstrap error: " << exc.Message);
|
||||
aContext.throwError((u"" SAL_WHERE ""_ustr).getStr(), exc.Message.getStr());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Linq;
|
||||
|
||||
namespace com.sun.star.uno
|
||||
{
|
||||
public static class NativeBootstrap
|
||||
{
|
||||
public static XComponentContext bootstrap()
|
||||
{
|
||||
Interop.bootstrap(null);
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class Interop
|
||||
{
|
||||
private const string BOOTSTRAP_LIBRARY = "net_bootstrap";
|
||||
|
||||
[DllImport(BOOTSTRAP_LIBRARY, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr bootstrap([MarshalAs(UnmanagedType.LPWStr)] string sParams);
|
||||
}
|
||||
}
|
||||
}
|
25
net_ure/source/bridge/helper/DisposeGuard.cs
Normal file
25
net_ure/source/bridge/helper/DisposeGuard.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
using com.sun.star.lang;
|
||||
|
||||
namespace com.sun.star.uno.helper
|
||||
{
|
||||
// This class can be used to auto-dispose UNO components
|
||||
// from managed code with a using block/statement.
|
||||
public class DisposeGuard : IDisposable
|
||||
{
|
||||
private readonly XComponent _component;
|
||||
public DisposeGuard(XComponent component) => _component = component;
|
||||
|
||||
public void Dispose() => _component?.dispose();
|
||||
}
|
||||
|
||||
}
|
56
net_ure/source/bridge/helper/StructHelper.cs
Normal file
56
net_ure/source/bridge/helper/StructHelper.cs
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace com.sun.star.uno.helper
|
||||
{
|
||||
internal static class StructHelper
|
||||
{
|
||||
private static Dictionary<Type, (Func<object[], object>, Type[])> _ctorCache;
|
||||
private static Dictionary<Type, (Action<object, object[]>, Type[])> _dtorCache;
|
||||
static StructHelper()
|
||||
{
|
||||
_ctorCache = new Dictionary<Type, (Func<object[], object>, Type[])>();
|
||||
_dtorCache = new Dictionary<Type, (Action<object, object[]>, Type[])>();
|
||||
}
|
||||
|
||||
public static (Func<object[], object>, Type[]) GetConstructor(Type type)
|
||||
{
|
||||
if (_ctorCache.TryGetValue(type, out (Func<object[], object>, Type[]) cached))
|
||||
return cached;
|
||||
|
||||
ConstructorInfo ctor = type.GetConstructors().First(c => c.GetParameters().Length > 0);
|
||||
|
||||
Func<object[], object> func = args => ctor.Invoke(args);
|
||||
Type[] paramTypes = ctor.GetParameters()
|
||||
.Select(p => TypeHelper.RemoveReference(p.ParameterType))
|
||||
.ToArray();
|
||||
|
||||
return _ctorCache[type] = (func, paramTypes);
|
||||
}
|
||||
|
||||
public static (Action<object, object[]>, Type[]) GetDeconstructor(Type type)
|
||||
{
|
||||
if (_dtorCache.TryGetValue(type, out (Action<object, object[]>, Type[]) cached))
|
||||
return cached;
|
||||
|
||||
MethodInfo dtor = type.GetMethod("Deconstruct", BindingFlags.Instance | BindingFlags.Public);
|
||||
|
||||
Action<object, object[]> action = (target, args) => dtor.Invoke(target, args);
|
||||
Type[] paramTypes = dtor.GetParameters()
|
||||
.Select(p => TypeHelper.RemoveReference(p.ParameterType))
|
||||
.ToArray();
|
||||
|
||||
return _dtorCache[type] = (action, paramTypes);
|
||||
}
|
||||
}
|
||||
}
|
125
net_ure/source/bridge/helper/TypeHelper.cs
Normal file
125
net_ure/source/bridge/helper/TypeHelper.cs
Normal file
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace com.sun.star.uno.helper
|
||||
{
|
||||
internal static class TypeHelper
|
||||
{
|
||||
private static List<Assembly> _assemblies;
|
||||
private static Dictionary<string, Type> _cache;
|
||||
|
||||
static TypeHelper()
|
||||
{
|
||||
_assemblies = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.OrderBy(a => !a.FullName.StartsWith("net_"))
|
||||
.ThenBy(a => a != Assembly.GetExecutingAssembly())
|
||||
.ToList();
|
||||
_cache = new Dictionary<string, Type>();
|
||||
|
||||
// TODO: verify this works as intended
|
||||
AppDomain.CurrentDomain.AssemblyLoad += (_, e) => _assemblies.Add(e.LoadedAssembly);
|
||||
}
|
||||
|
||||
public static Type RemoveReference(Type type) => type.IsByRef ? type.GetElementType() : type;
|
||||
|
||||
public static Type ParseType(string encoded)
|
||||
{
|
||||
if (_cache.TryGetValue(encoded, out Type cachedType))
|
||||
return cachedType;
|
||||
|
||||
string baseName = encoded;
|
||||
int arrayDims = 0;
|
||||
|
||||
int genericDepth = -1;
|
||||
int genericTypeCount = 0;
|
||||
foreach (char c in encoded)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '<':
|
||||
genericDepth++;
|
||||
break;
|
||||
case ',':
|
||||
if (genericDepth == 0)
|
||||
genericTypeCount++;
|
||||
break;
|
||||
case '>':
|
||||
if (genericDepth-- == 0)
|
||||
genericTypeCount++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Type[] genericTypes = new Type[genericTypeCount];
|
||||
|
||||
genericDepth = -1;
|
||||
int genericStart = -1;
|
||||
int genericIndex = 0;
|
||||
for (int i = 0; i < encoded.Length; i++)
|
||||
{
|
||||
char c = encoded[i];
|
||||
switch (c)
|
||||
{
|
||||
case '<':
|
||||
if (++genericDepth == 0)
|
||||
{
|
||||
baseName = encoded.Substring(0, i);
|
||||
genericStart = i + 1;
|
||||
}
|
||||
break;
|
||||
case ',':
|
||||
if (genericDepth == 0)
|
||||
{
|
||||
string genericType = encoded.Substring(genericStart, i - genericStart);
|
||||
genericTypes[genericIndex++] = ParseType(genericType);
|
||||
genericStart = i + 1;
|
||||
}
|
||||
break;
|
||||
case '>':
|
||||
if (genericDepth-- == 0)
|
||||
{
|
||||
string genericType = encoded.Substring(genericStart, i - genericStart);
|
||||
genericTypes[genericIndex++] = ParseType(genericType);
|
||||
genericStart = i + 1;
|
||||
}
|
||||
break;
|
||||
case ']':
|
||||
if (genericDepth == 0)
|
||||
{
|
||||
++arrayDims;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Type returnType = genericTypes.Length > 0
|
||||
? LoadType($"{baseName}`{genericTypes.Length}").MakeGenericType(genericTypes)
|
||||
: LoadType(baseName);
|
||||
|
||||
for (int i = 0; i < arrayDims; ++i)
|
||||
returnType = returnType.MakeArrayType();
|
||||
|
||||
return _cache[encoded] = returnType;
|
||||
}
|
||||
|
||||
private static Type LoadType(string name)
|
||||
{
|
||||
foreach (Assembly assembly in _assemblies)
|
||||
{
|
||||
Type t = assembly.GetType(name);
|
||||
if (t != null)
|
||||
return t;
|
||||
}
|
||||
throw new RuntimeException($"could not load type {name}", null);
|
||||
}
|
||||
}
|
||||
}
|
77
net_ure/source/bridge/helper/WeakBase.cs
Normal file
77
net_ure/source/bridge/helper/WeakBase.cs
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using com.sun.star.uno;
|
||||
using com.sun.star.lang;
|
||||
|
||||
namespace com.sun.star.uno.helper
|
||||
{
|
||||
// This class can be used as a helper base class for UNO interfaces.
|
||||
// It allows taking weak references to the object (com.sun.star.uno.XWeak)
|
||||
// and using the object from StarBasic (com.sun.star.lang.XTypeProvider).
|
||||
public class WeakBase : IQueryInterface, XWeak, XTypeProvider
|
||||
{
|
||||
private WeakAdapter _adapter;
|
||||
~WeakBase() => _adapter?.RaiseTargetDestructing();
|
||||
|
||||
private static readonly ConcurrentDictionary<Type, Type[]> _providedTypes;
|
||||
static WeakBase() => _providedTypes = new ConcurrentDictionary<Type, Type[]>();
|
||||
|
||||
// IQueryInterface
|
||||
public Any queryInterface(Type type)
|
||||
=> type.IsAssignableFrom(GetType()) ? new Any(type, this) : Any.VOID;
|
||||
|
||||
// XWeak
|
||||
public XAdapter queryAdapter()
|
||||
{
|
||||
if (_adapter == null)
|
||||
_adapter = new WeakAdapter(this);
|
||||
return _adapter;
|
||||
}
|
||||
|
||||
// XTypeProvider
|
||||
public Type[] getTypes()
|
||||
{
|
||||
return _providedTypes.GetOrAdd(GetType(),
|
||||
type => type.GetInterfaces()
|
||||
.Where(i => typeof(IQueryInterface).IsAssignableFrom(i))
|
||||
.ToArray()
|
||||
);
|
||||
}
|
||||
|
||||
public sbyte[] getImplementationId() => Array.Empty<sbyte>();
|
||||
|
||||
// An XAdapter implementation that holds a weak reference to an interface.
|
||||
private class WeakAdapter : IQueryInterface, XAdapter
|
||||
{
|
||||
private event Action _onDispose;
|
||||
|
||||
private WeakReference<IQueryInterface> _weakRef;
|
||||
public WeakAdapter(IQueryInterface obj)
|
||||
=> _weakRef = new WeakReference<IQueryInterface>(obj);
|
||||
|
||||
public void RaiseTargetDestructing() => _onDispose?.Invoke();
|
||||
|
||||
// IQueryInterface
|
||||
public Any queryInterface(Type type)
|
||||
=> type.IsAssignableFrom(GetType()) ? new Any(type, this) : Any.VOID;
|
||||
|
||||
// XAdapter
|
||||
public IQueryInterface queryAdapted()
|
||||
=> _weakRef.TryGetTarget(out IQueryInterface target) ? target : null;
|
||||
|
||||
public void addReference(XReference reference) => _onDispose += reference.dispose;
|
||||
public void removeReference(XReference reference) => _onDispose -= reference.dispose;
|
||||
}
|
||||
}
|
||||
}
|
40
net_ure/source/bridge/helper/WeakComponentBase.cs
Normal file
40
net_ure/source/bridge/helper/WeakComponentBase.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using com.sun.star.uno;
|
||||
using com.sun.star.lang;
|
||||
|
||||
namespace com.sun.star.uno.helper
|
||||
{
|
||||
// This class can be used as a helper base class for UNO interfaces.
|
||||
// It allows taking weak references to the object (com.sun.star.uno.XWeak),
|
||||
// using the object from StarBasic (com.sun.star.lang.XTypeProvider)
|
||||
// and explicitly controlling its lifetime (com.sun.star.lang.XComponent)
|
||||
public class WeakComponentBase : WeakBase, XComponent
|
||||
{
|
||||
private readonly List<XEventListener> _listeners;
|
||||
public WeakComponentBase() => _listeners = new List<XEventListener>();
|
||||
|
||||
// XComponent
|
||||
public void dispose()
|
||||
{
|
||||
EventObject e = new EventObject(this);
|
||||
foreach (XEventListener listener in _listeners)
|
||||
listener.disposing(e);
|
||||
_listeners.Clear();
|
||||
}
|
||||
|
||||
public void addEventListener(XEventListener listener) => _listeners.Add(listener);
|
||||
public void removeEventListener(XEventListener listener) => _listeners.Remove(listener);
|
||||
}
|
||||
}
|
50
net_ure/source/bridge/native/InteropMethods.cs
Normal file
50
net_ure/source/bridge/native/InteropMethods.cs
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace com.sun.star.uno.native
|
||||
{
|
||||
internal static class InteropMethods
|
||||
{
|
||||
private const string BOOTSTRAP_LIBRARY = "net_bootstrap";
|
||||
private const string UNO_LIBRARY = "net_uno";
|
||||
|
||||
[DllImport(BOOTSTRAP_LIBRARY, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr bootstrap(InteropContext pCtx);
|
||||
|
||||
[DllImport(BOOTSTRAP_LIBRARY, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr defaultBootstrap_InitialComponentContext(
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string sIniFile,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string sParams,
|
||||
InteropContext pCtx
|
||||
);
|
||||
|
||||
[DllImport(UNO_LIBRARY, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr allocateMemory(int nBytes);
|
||||
|
||||
[DllImport(UNO_LIBRARY, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
|
||||
public static extern void freeMemory(IntPtr pMemory);
|
||||
|
||||
[DllImport(UNO_LIBRARY, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
|
||||
public static extern void releaseProxy(IntPtr pBridgeHandle,
|
||||
IntPtr pInterfaceHandle, IntPtr pTypeHandle);
|
||||
|
||||
[DllImport(UNO_LIBRARY, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
|
||||
public static unsafe extern byte dispatchCall(
|
||||
IntPtr pBridgeHandle,
|
||||
IntPtr pInterfaceHandle,
|
||||
IntPtr pTypeHandle,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string sMethod,
|
||||
InteropValue* pNetArgs,
|
||||
InteropValue* pNetRet,
|
||||
InteropValue* pNetExc
|
||||
);
|
||||
}
|
||||
}
|
86
net_ure/source/bridge/native/InteropTypes.cs
Normal file
86
net_ure/source/bridge/native/InteropTypes.cs
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace com.sun.star.uno.native
|
||||
{
|
||||
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
|
||||
internal struct InteropValue
|
||||
{
|
||||
[FieldOffset(0)] public byte boolData; // (System.Bool is not blittable)
|
||||
[FieldOffset(0)] public sbyte byteData;
|
||||
[FieldOffset(0)] public char charData;
|
||||
[FieldOffset(0)] public short shortData;
|
||||
[FieldOffset(0)] public ushort unsigShortData;
|
||||
[FieldOffset(0)] public int longData;
|
||||
[FieldOffset(0)] public uint unsigLongData;
|
||||
[FieldOffset(0)] public long hyperData;
|
||||
[FieldOffset(0)] public ulong unsigHyperData;
|
||||
[FieldOffset(0)] public float floatData;
|
||||
[FieldOffset(0)] public double doubleData;
|
||||
[FieldOffset(0)] public IntPtr stringData;
|
||||
[FieldOffset(0)] public IntPtr typeData;
|
||||
[FieldOffset(0)] public Any anyData;
|
||||
[FieldOffset(0)] public int enumData;
|
||||
[FieldOffset(0)] public IntPtr structData;
|
||||
[FieldOffset(0)] public IntPtr exceptionData;
|
||||
[FieldOffset(0)] public Sequence sequenceData;
|
||||
[FieldOffset(0)] public IntPtr interfaceData;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Any
|
||||
{
|
||||
public IntPtr data;
|
||||
public IntPtr type;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Sequence
|
||||
{
|
||||
public IntPtr data;
|
||||
public int length;
|
||||
}
|
||||
};
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
|
||||
internal delegate IntPtr CreateProxyFunc(string pOid, string pInterfaceName, IntPtr pBridge,
|
||||
IntPtr pUnoInterface, IntPtr pTypeDesc);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
|
||||
internal delegate string LookupObjectIdFunc(IntPtr pNetInterface);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
|
||||
internal delegate IntPtr RegisterInterfaceFunc(IntPtr pNetInterface, string pOid, string pInterfaceName);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
|
||||
internal delegate IntPtr LookupInterfaceFunc(string pOid, string pInterfaceName);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
|
||||
internal delegate void RevokeInterfaceFunc(string pOid, string pInterfaceName);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
|
||||
internal delegate byte DispatchCallFunc(IntPtr pNetInterface, string pMethodName,
|
||||
IntPtr pArgs, IntPtr pRet, IntPtr pExc);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
|
||||
internal delegate void ThrowErrorFunc(string pMessage, string pWhere);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
internal struct InteropContext
|
||||
{
|
||||
public CreateProxyFunc createProxy;
|
||||
public LookupObjectIdFunc lookupObjectId;
|
||||
public RegisterInterfaceFunc registerInterface;
|
||||
public LookupInterfaceFunc lookupInterface;
|
||||
public RevokeInterfaceFunc revokeInterface;
|
||||
public DispatchCallFunc dispatchCall;
|
||||
public ThrowErrorFunc throwError;
|
||||
};
|
||||
}
|
608
net_ure/source/bridge/native/Marshaller.cs
Normal file
608
net_ure/source/bridge/native/Marshaller.cs
Normal file
|
@ -0,0 +1,608 @@
|
|||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using com.sun.star.uno.helper;
|
||||
|
||||
namespace com.sun.star.uno.native
|
||||
{
|
||||
internal class Marshaller
|
||||
{
|
||||
private readonly NetEnvironment _env;
|
||||
public Marshaller(NetEnvironment env) => _env = env;
|
||||
|
||||
public unsafe void MarshalObject(Type type, object src, InteropValue* value, bool destructValue)
|
||||
=> MarshalObject(type, src, (void*)value, destructValue);
|
||||
|
||||
public unsafe void UnmarshalObject(Type type, ref object dst, InteropValue* value, bool assignObject)
|
||||
=> UnmarshalObject(type, ref dst, (void*)value, assignObject);
|
||||
|
||||
private unsafe void MarshalObject(Type type, object source, void* value, bool destructValue)
|
||||
{
|
||||
switch (Type.GetTypeCode(type))
|
||||
{
|
||||
case TypeCode.Boolean:
|
||||
*(byte*)value = (byte)((bool)source ? 1 : 0);
|
||||
break;
|
||||
case TypeCode.SByte:
|
||||
*(sbyte*)value = (sbyte)source;
|
||||
break;
|
||||
case TypeCode.Char:
|
||||
*(char*)value = (char)source;
|
||||
break;
|
||||
case TypeCode.Int16:
|
||||
*(short*)value = (short)source;
|
||||
break;
|
||||
case TypeCode.UInt16:
|
||||
*(ushort*)value = (ushort)source;
|
||||
break;
|
||||
case TypeCode.Int32:
|
||||
*(int*)value = (int)source;
|
||||
break;
|
||||
case TypeCode.UInt32:
|
||||
*(uint*)value = (uint)source;
|
||||
break;
|
||||
case TypeCode.Int64:
|
||||
*(long*)value = (long)source;
|
||||
break;
|
||||
case TypeCode.UInt64:
|
||||
*(ulong*)value = (ulong)source;
|
||||
break;
|
||||
case TypeCode.Single:
|
||||
*(float*)value = (float)source;
|
||||
break;
|
||||
case TypeCode.Double:
|
||||
*(double*)value = (double)source;
|
||||
break;
|
||||
case TypeCode.String:
|
||||
{
|
||||
IntPtr* valueStr = (IntPtr*)value;
|
||||
string netStr = (string)source;
|
||||
|
||||
if (destructValue && *valueStr != IntPtr.Zero)
|
||||
InteropMethods.freeMemory(*valueStr);
|
||||
|
||||
*valueStr = MarshalString(netStr);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (type == typeof(void))
|
||||
{
|
||||
*(IntPtr*)value = IntPtr.Zero;
|
||||
}
|
||||
else if (type == typeof(Type))
|
||||
{
|
||||
IntPtr* valueType = (IntPtr*)value;
|
||||
Type netType = (Type)source;
|
||||
|
||||
if (destructValue && *valueType != IntPtr.Zero)
|
||||
InteropMethods.freeMemory(*valueType);
|
||||
*valueType = MarshalString(netType.FullName);
|
||||
}
|
||||
else if (type == typeof(Any))
|
||||
{
|
||||
InteropValue.Any* valueAny = (InteropValue.Any*)value;
|
||||
Any netAny = (Any)source;
|
||||
|
||||
switch (Type.GetTypeCode(netAny.Type))
|
||||
{
|
||||
case TypeCode.Boolean:
|
||||
case TypeCode.SByte:
|
||||
case TypeCode.Char:
|
||||
case TypeCode.Int16:
|
||||
case TypeCode.UInt16:
|
||||
case TypeCode.Int32:
|
||||
case TypeCode.UInt32:
|
||||
case TypeCode.Single:
|
||||
MarshalObject(netAny.Type, netAny.Value, (void*)&valueAny->data, destructValue);
|
||||
break;
|
||||
case TypeCode.Int64:
|
||||
case TypeCode.UInt64:
|
||||
case TypeCode.Double:
|
||||
{
|
||||
int size = SizeOf(netAny.Type);
|
||||
if (size <= IntPtr.Size)
|
||||
MarshalObject(netAny.Type, netAny.Value, (void*)&valueAny->data, destructValue);
|
||||
else
|
||||
{
|
||||
IntPtr mem = InteropMethods.allocateMemory(size);
|
||||
MarshalObject(netAny.Type, netAny.Value, (void*)mem, false);
|
||||
if (destructValue)
|
||||
InteropMethods.freeMemory(valueAny->data);
|
||||
valueAny->data = mem;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (netAny.Type == typeof(Any) || netAny.Type.IsArray)
|
||||
{
|
||||
IntPtr mem = InteropMethods.allocateMemory(SizeOf(netAny.Type));
|
||||
MarshalObject(netAny.Type, netAny.Value, (void*)mem, false);
|
||||
if (destructValue)
|
||||
InteropMethods.freeMemory(valueAny->data);
|
||||
valueAny->data = mem;
|
||||
}
|
||||
else
|
||||
{
|
||||
MarshalObject(netAny.Type, netAny.Value, (void*)&valueAny->data, destructValue);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
MarshalObject(typeof(Type), netAny.Type, (void*)&valueAny->type, destructValue);
|
||||
}
|
||||
else if (type.IsEnum)
|
||||
{
|
||||
*(int*)value = (int)source;
|
||||
}
|
||||
else if (type.IsArray)
|
||||
{
|
||||
InteropValue.Sequence* valueSeq = (InteropValue.Sequence*)value;
|
||||
Array netArray = (Array)source;
|
||||
|
||||
Type elemType = type.GetElementType();
|
||||
int elemSize = SizeOf(elemType);
|
||||
|
||||
int memSize = elemSize * netArray.Length;
|
||||
IntPtr mem = InteropMethods.allocateMemory(memSize);
|
||||
|
||||
switch (Type.GetTypeCode(elemType))
|
||||
{
|
||||
case TypeCode.Boolean:
|
||||
fixed (void* src = (bool[])netArray)
|
||||
Buffer.MemoryCopy(src, (void*)mem, memSize, memSize);
|
||||
break;
|
||||
case TypeCode.SByte:
|
||||
fixed (void* src = (sbyte[])netArray)
|
||||
Buffer.MemoryCopy(src, (void*)mem, memSize, memSize);
|
||||
break;
|
||||
case TypeCode.Char:
|
||||
fixed (void* src = (char[])netArray)
|
||||
Buffer.MemoryCopy(src, (void*)mem, memSize, memSize);
|
||||
break;
|
||||
case TypeCode.Int16:
|
||||
fixed (void* src = (short[])netArray)
|
||||
Buffer.MemoryCopy(src, (void*)mem, memSize, memSize);
|
||||
break;
|
||||
case TypeCode.UInt16:
|
||||
fixed (void* src = (ushort[])netArray)
|
||||
Buffer.MemoryCopy(src, (void*)mem, memSize, memSize);
|
||||
break;
|
||||
case TypeCode.Int32:
|
||||
fixed (void* src = (int[])netArray)
|
||||
Buffer.MemoryCopy(src, (void*)mem, memSize, memSize);
|
||||
break;
|
||||
case TypeCode.UInt32:
|
||||
fixed (void* src = (uint[])netArray)
|
||||
Buffer.MemoryCopy(src, (void*)mem, memSize, memSize);
|
||||
break;
|
||||
case TypeCode.Int64:
|
||||
fixed (void* src = (long[])netArray)
|
||||
Buffer.MemoryCopy(src, (void*)mem, memSize, memSize);
|
||||
break;
|
||||
case TypeCode.UInt64:
|
||||
fixed (void* src = (ulong[])netArray)
|
||||
Buffer.MemoryCopy(src, (void*)mem, memSize, memSize);
|
||||
break;
|
||||
case TypeCode.Single:
|
||||
fixed (void* src = (float[])netArray)
|
||||
Buffer.MemoryCopy(src, (void*)mem, memSize, memSize);
|
||||
break;
|
||||
case TypeCode.Double:
|
||||
fixed (void* src = (double[])netArray)
|
||||
Buffer.MemoryCopy(src, (void*)mem, memSize, memSize);
|
||||
break;
|
||||
default:
|
||||
if (elemType.IsEnum)
|
||||
{
|
||||
fixed (void* src = (int[])netArray)
|
||||
Buffer.MemoryCopy(src, (void*)mem, memSize, memSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < netArray.Length; i++)
|
||||
MarshalObject(elemType, netArray.GetValue(i), (void*)(mem + elemSize * i), destructValue);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (destructValue && valueSeq->data != IntPtr.Zero)
|
||||
InteropMethods.freeMemory(valueSeq->data);
|
||||
|
||||
valueSeq->data = mem;
|
||||
valueSeq->length = netArray.Length;
|
||||
}
|
||||
else if (typeof(IQueryInterface).IsAssignableFrom(type))
|
||||
{
|
||||
*(IntPtr*)value = source is NativeUnoProxy nup
|
||||
? _env.LookupInterface(nup.Oid, nup.Type)
|
||||
: _env.RegisterLocal(source, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
IntPtr* valueStruct = (IntPtr*)value;
|
||||
|
||||
(Action<object, object[]> dtor, Type[] fieldTypes) = StructHelper.GetDeconstructor(type);
|
||||
object[] fields = new object[fieldTypes.Length];
|
||||
dtor.Invoke(source, fields);
|
||||
|
||||
IntPtr mem = InteropMethods.allocateMemory(fieldTypes.Sum(SizeOf));
|
||||
|
||||
int offset = 0;
|
||||
for (int i = 0; i < fieldTypes.Length; i++)
|
||||
{
|
||||
MarshalObject(fieldTypes[i], fields[i], (void*)(mem + offset), destructValue);
|
||||
offset += SizeOf(fieldTypes[i]);
|
||||
}
|
||||
|
||||
if (destructValue && *valueStruct != IntPtr.Zero)
|
||||
InteropMethods.freeMemory(*valueStruct);
|
||||
|
||||
*valueStruct = mem;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void UnmarshalObject(Type type, ref object target, void* value, bool assignObject)
|
||||
{
|
||||
switch (Type.GetTypeCode(type))
|
||||
{
|
||||
case TypeCode.Boolean:
|
||||
if (assignObject)
|
||||
target = *(byte*)value != 0;
|
||||
break;
|
||||
case TypeCode.SByte:
|
||||
if (assignObject)
|
||||
target = *(byte*)value;
|
||||
break;
|
||||
case TypeCode.Char:
|
||||
if (assignObject)
|
||||
target = *(char*)value;
|
||||
break;
|
||||
case TypeCode.Int16:
|
||||
if (assignObject)
|
||||
target = *(short*)value;
|
||||
break;
|
||||
case TypeCode.UInt16:
|
||||
if (assignObject)
|
||||
target = *(ushort*)value;
|
||||
break;
|
||||
case TypeCode.Int32:
|
||||
if (assignObject)
|
||||
target = *(int*)value;
|
||||
break;
|
||||
case TypeCode.UInt32:
|
||||
if (assignObject)
|
||||
target = *(uint*)value;
|
||||
break;
|
||||
case TypeCode.Int64:
|
||||
if (assignObject)
|
||||
target = *(long*)value;
|
||||
break;
|
||||
case TypeCode.UInt64:
|
||||
if (assignObject)
|
||||
target = *(ulong*)value;
|
||||
break;
|
||||
case TypeCode.Single:
|
||||
if (assignObject)
|
||||
target = *(float*)value;
|
||||
break;
|
||||
case TypeCode.Double:
|
||||
if (assignObject)
|
||||
target = *(double*)value;
|
||||
break;
|
||||
case TypeCode.String:
|
||||
{
|
||||
IntPtr valueStr = *(IntPtr*)value;
|
||||
if (assignObject)
|
||||
target = UnmarshalString(valueStr);
|
||||
else
|
||||
InteropMethods.freeMemory(valueStr);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (type == typeof(void))
|
||||
{
|
||||
if (assignObject)
|
||||
target = null;
|
||||
}
|
||||
else if (type == typeof(Type))
|
||||
{
|
||||
IntPtr valueType = *(IntPtr*)value;
|
||||
if (assignObject)
|
||||
target = TypeHelper.ParseType(UnmarshalString(valueType));
|
||||
else
|
||||
InteropMethods.freeMemory(valueType);
|
||||
}
|
||||
else if (type == typeof(Any))
|
||||
{
|
||||
InteropValue.Any* valueAny = (InteropValue.Any*)value;
|
||||
|
||||
object contents = null;
|
||||
Type containedType = TypeHelper.ParseType(UnmarshalString(valueAny->type));
|
||||
|
||||
if (assignObject)
|
||||
{
|
||||
switch (Type.GetTypeCode(containedType))
|
||||
{
|
||||
case TypeCode.Boolean:
|
||||
case TypeCode.SByte:
|
||||
case TypeCode.Char:
|
||||
case TypeCode.Int16:
|
||||
case TypeCode.UInt16:
|
||||
case TypeCode.Int32:
|
||||
case TypeCode.UInt32:
|
||||
case TypeCode.Single:
|
||||
UnmarshalObject(containedType, ref contents, (void*)&valueAny->data, true);
|
||||
break;
|
||||
case TypeCode.Int64:
|
||||
case TypeCode.UInt64:
|
||||
case TypeCode.Double:
|
||||
{
|
||||
int size = SizeOf(containedType);
|
||||
if (size <= IntPtr.Size)
|
||||
{
|
||||
UnmarshalObject(containedType, ref contents, (void*)&valueAny->data, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnmarshalObject(containedType, ref contents, (void*)valueAny->data, true);
|
||||
InteropMethods.freeMemory(valueAny->data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (containedType == typeof(Any) || containedType.IsArray)
|
||||
{
|
||||
UnmarshalObject(containedType, ref contents, (void*)valueAny->data, true);
|
||||
InteropMethods.freeMemory(valueAny->data);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnmarshalObject(containedType, ref contents, (void*)&valueAny->data, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
target = new Any(containedType, contents);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (Type.GetTypeCode(containedType))
|
||||
{
|
||||
case TypeCode.Boolean:
|
||||
case TypeCode.SByte:
|
||||
case TypeCode.Char:
|
||||
case TypeCode.Int16:
|
||||
case TypeCode.UInt16:
|
||||
case TypeCode.Int32:
|
||||
case TypeCode.UInt32:
|
||||
case TypeCode.Single:
|
||||
break;
|
||||
case TypeCode.Int64:
|
||||
case TypeCode.UInt64:
|
||||
case TypeCode.Double:
|
||||
if (SizeOf(containedType) > IntPtr.Size)
|
||||
InteropMethods.freeMemory(valueAny->data);
|
||||
break;
|
||||
default:
|
||||
if (containedType == typeof(Any) || containedType.IsArray)
|
||||
{
|
||||
UnmarshalObject(containedType, ref contents, (void*)valueAny->data, false);
|
||||
InteropMethods.freeMemory(valueAny->data);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnmarshalObject(containedType, ref contents, (void*)&valueAny->data, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type.IsEnum)
|
||||
{
|
||||
target = *(int*)value;
|
||||
}
|
||||
else if (type.IsArray)
|
||||
{
|
||||
InteropValue.Sequence* valueSeq = (InteropValue.Sequence*)value;
|
||||
|
||||
Type elemType = type.GetElementType();
|
||||
int elemSize = SizeOf(elemType);
|
||||
|
||||
if (assignObject)
|
||||
{
|
||||
int memSize = elemSize * valueSeq->length;
|
||||
Array netArray = Array.CreateInstance(elemType, valueSeq->length);
|
||||
|
||||
switch (Type.GetTypeCode(elemType))
|
||||
{
|
||||
case TypeCode.Boolean:
|
||||
fixed (void* dst = (bool[])netArray)
|
||||
Buffer.MemoryCopy((void*)valueSeq->data, dst, memSize, memSize);
|
||||
break;
|
||||
case TypeCode.SByte:
|
||||
fixed (void* dst = (sbyte[])netArray)
|
||||
Buffer.MemoryCopy((void*)valueSeq->data, dst, memSize, memSize);
|
||||
break;
|
||||
case TypeCode.Char:
|
||||
fixed (void* dst = (char[])netArray)
|
||||
Buffer.MemoryCopy((void*)valueSeq->data, dst, memSize, memSize);
|
||||
break;
|
||||
case TypeCode.Int16:
|
||||
fixed (void* dst = (short[])netArray)
|
||||
Buffer.MemoryCopy((void*)valueSeq->data, dst, memSize, memSize);
|
||||
break;
|
||||
case TypeCode.UInt16:
|
||||
fixed (void* dst = (ushort[])netArray)
|
||||
Buffer.MemoryCopy((void*)valueSeq->data, dst, memSize, memSize);
|
||||
break;
|
||||
case TypeCode.Int32:
|
||||
fixed (void* dst = (int[])netArray)
|
||||
Buffer.MemoryCopy((void*)valueSeq->data, dst, memSize, memSize);
|
||||
break;
|
||||
case TypeCode.UInt32:
|
||||
fixed (void* dst = (uint[])netArray)
|
||||
Buffer.MemoryCopy((void*)valueSeq->data, dst, memSize, memSize);
|
||||
break;
|
||||
case TypeCode.Int64:
|
||||
fixed (void* dst = (long[])netArray)
|
||||
Buffer.MemoryCopy((void*)valueSeq->data, dst, memSize, memSize);
|
||||
break;
|
||||
case TypeCode.UInt64:
|
||||
fixed (void* dst = (ulong[])netArray)
|
||||
Buffer.MemoryCopy((void*)valueSeq->data, dst, memSize, memSize);
|
||||
break;
|
||||
case TypeCode.Single:
|
||||
fixed (void* dst = (float[])netArray)
|
||||
Buffer.MemoryCopy((void*)valueSeq->data, dst, memSize, memSize);
|
||||
break;
|
||||
case TypeCode.Double:
|
||||
fixed (void* dst = (double[])netArray)
|
||||
Buffer.MemoryCopy((void*)valueSeq->data, dst, memSize, memSize);
|
||||
break;
|
||||
default:
|
||||
if (elemType.IsEnum)
|
||||
{
|
||||
fixed (void* dst = (int[])netArray)
|
||||
Buffer.MemoryCopy((void*)valueSeq->data, dst, memSize, memSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
object inner = null;
|
||||
for (int i = 0; i < netArray.Length; i++)
|
||||
{
|
||||
UnmarshalObject(elemType, ref inner, (void*)(valueSeq->data + elemSize * i), true);
|
||||
netArray.SetValue(inner, i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
target = netArray;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (Type.GetTypeCode(elemType))
|
||||
{
|
||||
case TypeCode.Boolean:
|
||||
case TypeCode.SByte:
|
||||
case TypeCode.Char:
|
||||
case TypeCode.Int16:
|
||||
case TypeCode.UInt16:
|
||||
case TypeCode.Int32:
|
||||
case TypeCode.UInt32:
|
||||
case TypeCode.Int64:
|
||||
case TypeCode.UInt64:
|
||||
case TypeCode.Single:
|
||||
case TypeCode.Double:
|
||||
break;
|
||||
default:
|
||||
if (elemType.IsEnum || typeof(IQueryInterface).IsAssignableFrom(type))
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
object dummy = null;
|
||||
for (int i = 0; i < valueSeq->length; i++)
|
||||
UnmarshalObject(elemType, ref dummy, (void*)(valueSeq->data + elemSize * i), false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
InteropMethods.freeMemory(valueSeq->data);
|
||||
}
|
||||
else if (typeof(IQueryInterface).IsAssignableFrom(type))
|
||||
{
|
||||
if (assignObject)
|
||||
target = _env.GetRegisteredObject(*(IntPtr*)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
IntPtr valueStruct = *(IntPtr*)value;
|
||||
|
||||
(Func<object[], object> ctor, Type[] paramTypes) = StructHelper.GetConstructor(type);
|
||||
if (assignObject)
|
||||
{
|
||||
object[] args = new object[paramTypes.Length];
|
||||
int offset = 0;
|
||||
for (int i = 0; i < paramTypes.Length; i++)
|
||||
{
|
||||
UnmarshalObject(paramTypes[i], ref args[i], (void*)(valueStruct + offset), true);
|
||||
offset += SizeOf(paramTypes[i]);
|
||||
}
|
||||
target = ctor(args);
|
||||
}
|
||||
else
|
||||
{
|
||||
object dummy = null;
|
||||
int offset = 0;
|
||||
for (int i = 0; i < paramTypes.Length; i++)
|
||||
{
|
||||
UnmarshalObject(paramTypes[i], ref dummy, (void*)(valueStruct + offset), false);
|
||||
offset += SizeOf(paramTypes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
InteropMethods.freeMemory(valueStruct);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe IntPtr MarshalString(string str)
|
||||
{
|
||||
char* buffer = (char*)InteropMethods.allocateMemory((str.Length + 1) * sizeof(char));
|
||||
fixed (char* data = str)
|
||||
{
|
||||
Buffer.MemoryCopy(data, buffer, str.Length * sizeof(char), str.Length * sizeof(char));
|
||||
buffer[str.Length] = '\0';
|
||||
}
|
||||
return (IntPtr)buffer;
|
||||
}
|
||||
|
||||
private string UnmarshalString(IntPtr ptr)
|
||||
{
|
||||
string s = Marshal.PtrToStringUni(ptr);
|
||||
InteropMethods.freeMemory(ptr);
|
||||
return s;
|
||||
}
|
||||
|
||||
private int SizeOf(Type type)
|
||||
{
|
||||
switch (Type.GetTypeCode(type))
|
||||
{
|
||||
case TypeCode.Boolean: return sizeof(bool);
|
||||
case TypeCode.SByte: return sizeof(sbyte);
|
||||
case TypeCode.Char: return sizeof(char);
|
||||
case TypeCode.Int16: return sizeof(short);
|
||||
case TypeCode.UInt16: return sizeof(ushort);
|
||||
case TypeCode.Int32: return sizeof(int);
|
||||
case TypeCode.UInt32: return sizeof(uint);
|
||||
case TypeCode.Int64: return sizeof(long);
|
||||
case TypeCode.UInt64: return sizeof(ulong);
|
||||
case TypeCode.Single: return sizeof(float);
|
||||
case TypeCode.Double: return sizeof(double);
|
||||
}
|
||||
if (type.IsEnum)
|
||||
return sizeof(int);
|
||||
else if (type.IsArray)
|
||||
return IntPtr.Size + sizeof(int);
|
||||
else if (type == typeof(Any))
|
||||
return IntPtr.Size * 2;
|
||||
return IntPtr.Size;
|
||||
}
|
||||
}
|
||||
}
|
49
net_ure/source/bridge/native/NativeBootstrap.cs
Normal file
49
net_ure/source/bridge/native/NativeBootstrap.cs
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using com.sun.star.uno.native;
|
||||
|
||||
namespace com.sun.star.uno
|
||||
{
|
||||
public static class NativeBootstrap
|
||||
{
|
||||
private static LinkedList<WeakReference<NetEnvironment>> _environments;
|
||||
static NativeBootstrap() => _environments = new LinkedList<WeakReference<NetEnvironment>>();
|
||||
|
||||
public static XComponentContext bootstrap()
|
||||
{
|
||||
NetEnvironment env = new NetEnvironment();
|
||||
_environments.AddLast(new WeakReference<NetEnvironment>(env));
|
||||
|
||||
IntPtr result = InteropMethods.bootstrap(env.Context);
|
||||
return (XComponentContext)env.GetRegisteredObject(result);
|
||||
}
|
||||
|
||||
public static XComponentContext defaultBootstrap_InitialComponentContext(
|
||||
string iniFile = null, IDictionary<string, string> parameters = null)
|
||||
{
|
||||
iniFile = string.IsNullOrWhiteSpace(iniFile) ? null : iniFile;
|
||||
|
||||
string joinedParams = string.Join("|",
|
||||
parameters?.Select(p => $"{p.Key}={p.Value}") ?? Array.Empty<string>());
|
||||
joinedParams = string.IsNullOrWhiteSpace(joinedParams) ? null : joinedParams;
|
||||
|
||||
NetEnvironment env = new NetEnvironment();
|
||||
_environments.AddLast(new WeakReference<NetEnvironment>(env));
|
||||
|
||||
IntPtr result = InteropMethods.defaultBootstrap_InitialComponentContext(
|
||||
iniFile, joinedParams, env.Context);
|
||||
return (XComponentContext)env.GetRegisteredObject(result);
|
||||
}
|
||||
}
|
||||
}
|
58
net_ure/source/bridge/native/NativeUnoProxy.cs
Normal file
58
net_ure/source/bridge/native/NativeUnoProxy.cs
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
using com.sun.star.uno;
|
||||
|
||||
namespace com.sun.star.uno.native
|
||||
{
|
||||
internal class NativeUnoProxy : DispatchProxy
|
||||
{
|
||||
private IntPtr _bridgeHandle;
|
||||
private IntPtr _interfaceHandle;
|
||||
private IntPtr _typeHandle;
|
||||
private NetEnvironment _env;
|
||||
|
||||
public string Oid { get; private set; }
|
||||
public Type Type { get; private set; }
|
||||
|
||||
~NativeUnoProxy() => _env.ReleaseProxy(this, _bridgeHandle, _interfaceHandle, _typeHandle);
|
||||
|
||||
public static object CreateProxy(string oid, Type interfaceType,
|
||||
IntPtr pBridge, IntPtr pUnoInterface, IntPtr pTypeDesc, NetEnvironment env)
|
||||
{
|
||||
if (!typeof(IQueryInterface).IsAssignableFrom(interfaceType))
|
||||
throw new RuntimeException($"interfaceType must be IQueryInterface or a derived interface, was {interfaceType}", null);
|
||||
|
||||
MethodInfo method = typeof(DispatchProxy).GetMethod("Create", Type.EmptyTypes);
|
||||
MethodInfo typedMethod = method.MakeGenericMethod(interfaceType, typeof(NativeUnoProxy));
|
||||
|
||||
NativeUnoProxy proxy = (NativeUnoProxy)typedMethod.Invoke(null, null);
|
||||
proxy.Oid = oid;
|
||||
proxy.Type = interfaceType;
|
||||
proxy._bridgeHandle = pBridge;
|
||||
proxy._interfaceHandle = pUnoInterface;
|
||||
proxy._typeHandle = pTypeDesc;
|
||||
proxy._env = env;
|
||||
|
||||
return proxy;
|
||||
}
|
||||
|
||||
protected override object Invoke(MethodInfo targetMethod, object[] args)
|
||||
=> _env.InvokeMethod(targetMethod, args, _bridgeHandle, _interfaceHandle, _typeHandle);
|
||||
|
||||
public override bool Equals(object obj) => obj is NativeUnoProxy nup && Oid == nup.Oid;
|
||||
public override int GetHashCode() => Oid.GetHashCode();
|
||||
public override string ToString() => $"UNO Proxy {{ OID = {Oid}, Interface = {Type} }}";
|
||||
}
|
||||
}
|
227
net_ure/source/bridge/native/NetEnvironment.cs
Normal file
227
net_ure/source/bridge/native/NetEnvironment.cs
Normal file
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using com.sun.star.uno.helper;
|
||||
|
||||
namespace com.sun.star.uno.native
|
||||
{
|
||||
internal class NetEnvironment
|
||||
{
|
||||
public InteropContext Context { get; }
|
||||
|
||||
private readonly Marshaller _marshaller;
|
||||
private readonly WeakIndexTable _indices;
|
||||
private readonly WeakOidTypeTable _locals;
|
||||
private readonly WeakOidTypeTable _proxies;
|
||||
private readonly string _oidSuffix;
|
||||
private readonly Dictionary<int, string> _oids;
|
||||
|
||||
public NetEnvironment()
|
||||
{
|
||||
Context = new InteropContext()
|
||||
{
|
||||
createProxy = CreateProxy,
|
||||
lookupObjectId = LookupOid,
|
||||
registerInterface = RegisterInterface,
|
||||
lookupInterface = LookupInterface,
|
||||
revokeInterface = RevokeInterface,
|
||||
dispatchCall = DispatchCall,
|
||||
throwError = ThrowError,
|
||||
};
|
||||
|
||||
_marshaller = new Marshaller(this);
|
||||
_indices = new WeakIndexTable();
|
||||
_locals = new WeakOidTypeTable();
|
||||
_proxies = new WeakOidTypeTable();
|
||||
_oidSuffix = $";net[0];{Guid.NewGuid()}";
|
||||
_oids = new Dictionary<int, string>();
|
||||
}
|
||||
|
||||
public IntPtr CreateProxy(string oid, string interfaceName,
|
||||
IntPtr pBridge, IntPtr pUnoInterface, IntPtr pTypeDesc)
|
||||
{
|
||||
Type interfaceType = TypeHelper.ParseType(interfaceName);
|
||||
object proxy = NativeUnoProxy.CreateProxy(oid, interfaceType,
|
||||
pBridge, pUnoInterface, pTypeDesc, this);
|
||||
int index = _indices.Register(proxy);
|
||||
_oids.Add(index, oid);
|
||||
_proxies.RegisterInterface(proxy, oid, interfaceType);
|
||||
return (IntPtr)index;
|
||||
}
|
||||
|
||||
public string LookupOid(IntPtr pObject) => _oids[(int)pObject];
|
||||
|
||||
public IntPtr RegisterInterface(IntPtr pObject, string pOid, string pInterfaceName)
|
||||
{
|
||||
Type interfaceType = TypeHelper.ParseType(pInterfaceName);
|
||||
object obj = _indices.Lookup((int)pObject);
|
||||
obj = (obj is NativeUnoProxy ? _proxies : _locals)
|
||||
.RegisterInterface(obj, pOid, interfaceType);
|
||||
return (IntPtr)_indices.Register(obj);
|
||||
}
|
||||
|
||||
public IntPtr RegisterLocal(object obj, Type interfaceType)
|
||||
{
|
||||
int index = _indices.Register(obj);
|
||||
if (!_oids.ContainsKey(index))
|
||||
{
|
||||
string oid = $"{index}{_oidSuffix}";
|
||||
_oids.Add(index, oid);
|
||||
}
|
||||
_locals.RegisterInterface(obj, _oids[index], interfaceType);
|
||||
return (IntPtr)index;
|
||||
}
|
||||
|
||||
public IntPtr LookupInterface(string pOid, string pInterfaceName)
|
||||
{
|
||||
Type interfaceType = TypeHelper.ParseType(pInterfaceName);
|
||||
return LookupInterface(pOid, interfaceType);
|
||||
}
|
||||
public IntPtr LookupInterface(string pOid, Type type)
|
||||
{
|
||||
object obj = _proxies.GetInterface(pOid, type)
|
||||
?? _locals.GetInterface(pOid, type);
|
||||
return (IntPtr)_indices.Register(obj);
|
||||
}
|
||||
|
||||
public void RevokeInterface(string pOid, string pInterfaceName)
|
||||
{
|
||||
Type interfaceType = TypeHelper.ParseType(pInterfaceName);
|
||||
if (!_proxies.RevokeInterface(pOid, interfaceType))
|
||||
_locals.RevokeInterface(pOid, interfaceType);
|
||||
}
|
||||
|
||||
public void ThrowError(string pWhere, string pMessage)
|
||||
{
|
||||
throw new RuntimeException($"{pMessage} at {pWhere}", null);
|
||||
}
|
||||
|
||||
public object GetRegisteredObject(IntPtr pIndex)
|
||||
{
|
||||
return _indices.Lookup((int)pIndex);
|
||||
}
|
||||
|
||||
public unsafe void ReleaseProxy(NativeUnoProxy nup,
|
||||
IntPtr pBridge, IntPtr pUnoInterface, IntPtr pTypeDesc)
|
||||
{
|
||||
_oids.Remove(_indices.Register(nup));
|
||||
_proxies.RevokeInterface(nup.Oid, nup.Type);
|
||||
InteropMethods.releaseProxy(pBridge, pUnoInterface, pTypeDesc);
|
||||
}
|
||||
|
||||
public unsafe object InvokeMethod(MethodInfo targetMethod, object[] args,
|
||||
IntPtr bridgeHandle, IntPtr interfaceHandle, IntPtr typeHandle)
|
||||
{
|
||||
ParameterInfo[] parameters = targetMethod.GetParameters();
|
||||
|
||||
InteropValue* values = stackalloc InteropValue[parameters.Length + 2];
|
||||
InteropValue* retVal = &values[parameters.Length];
|
||||
InteropValue* excVal = &values[parameters.Length + 1];
|
||||
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
ParameterInfo param = parameters[i];
|
||||
Type paramType = TypeHelper.RemoveReference(param.ParameterType);
|
||||
bool isInOrInOut = !(param.ParameterType.IsByRef && param.IsOut);
|
||||
if (isInOrInOut)
|
||||
_marshaller.MarshalObject(paramType, args[i], &values[i], false);
|
||||
}
|
||||
|
||||
bool error = InteropMethods.dispatchCall(
|
||||
bridgeHandle, interfaceHandle, typeHandle,
|
||||
targetMethod.Name, values, retVal, excVal) == 0;
|
||||
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
ParameterInfo param = parameters[i];
|
||||
Type paramType = TypeHelper.RemoveReference(param.ParameterType);
|
||||
bool isInOutOrOut = param.ParameterType.IsByRef;
|
||||
if (isInOutOrOut)
|
||||
_marshaller.UnmarshalObject(paramType, ref args[i], &values[i], true);
|
||||
}
|
||||
|
||||
if (error)
|
||||
{
|
||||
object exception = null;
|
||||
_marshaller.UnmarshalObject(typeof(Any), ref exception, excVal, true);
|
||||
throw (Exception)((Any)exception).Value;
|
||||
}
|
||||
|
||||
if (targetMethod.ReturnType != typeof(void))
|
||||
{
|
||||
object result = null;
|
||||
_marshaller.UnmarshalObject(targetMethod.ReturnType, ref result, retVal, true);
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public unsafe byte DispatchCall(IntPtr pNetInterface, string pMethodName,
|
||||
IntPtr pArgs, IntPtr pRet, IntPtr pExc)
|
||||
{
|
||||
try
|
||||
{
|
||||
int methodNameStart = pMethodName.IndexOf(':') + 2;
|
||||
int methodNameEnd = pMethodName.IndexOf(':', methodNameStart);
|
||||
if (methodNameEnd > methodNameStart)
|
||||
pMethodName = pMethodName.Substring(methodNameStart, methodNameEnd - methodNameStart);
|
||||
else
|
||||
pMethodName = pMethodName.Substring(methodNameStart);
|
||||
|
||||
object target = _indices.Lookup((int)pNetInterface);
|
||||
if (target == null)
|
||||
throw new RuntimeException($"{pMethodName} was called on a null or unregistered interface", null);
|
||||
|
||||
Type targetType = target.GetType();
|
||||
MethodInfo targetMethod = targetType.GetMethod(pMethodName,
|
||||
BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
|
||||
if (targetMethod == null)
|
||||
throw new RuntimeException($"could not find method {pMethodName} on interface {target.GetType()}", null);
|
||||
|
||||
ParameterInfo[] parameters = targetMethod.GetParameters();
|
||||
object[] args = new object[parameters.Length];
|
||||
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
ParameterInfo param = parameters[i];
|
||||
Type paramType = TypeHelper.RemoveReference(param.ParameterType);
|
||||
bool isInOrInOut = !(param.ParameterType.IsByRef && param.IsOut);
|
||||
if (isInOrInOut)
|
||||
_marshaller.UnmarshalObject(paramType, ref args[i], &((InteropValue*)(void*)pArgs)[i], true);
|
||||
}
|
||||
|
||||
object ret = targetMethod.Invoke(target, args);
|
||||
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
ParameterInfo param = parameters[i];
|
||||
Type paramType = TypeHelper.RemoveReference(param.ParameterType);
|
||||
bool isInOutOrOut = param.ParameterType.IsByRef;
|
||||
if (isInOutOrOut)
|
||||
_marshaller.MarshalObject(paramType, args[i], &((InteropValue*)(void*)pArgs)[i], false);
|
||||
}
|
||||
|
||||
if (targetMethod.ReturnType != typeof(void))
|
||||
_marshaller.MarshalObject(targetMethod.ReturnType, ret, (InteropValue*)(void*)pRet, false);
|
||||
return 1;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_marshaller.MarshalObject(typeof(Any), new Any(exception.InnerException),
|
||||
(InteropValue*)(void*)pExc, false);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
103
net_ure/source/bridge/native/WeakIndexTable.cs
Normal file
103
net_ure/source/bridge/native/WeakIndexTable.cs
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace com.sun.star.uno.native
|
||||
{
|
||||
internal class WeakIndexTable
|
||||
{
|
||||
private readonly Dictionary<int, WeakReference<object>> _objectByIndex;
|
||||
private readonly Dictionary<WeakReference<object>, int> _indexByObject;
|
||||
private readonly List<int> _cleanupIndices;
|
||||
private readonly object _lock;
|
||||
|
||||
private int _counter;
|
||||
private int _updateOps;
|
||||
|
||||
public WeakIndexTable()
|
||||
{
|
||||
_objectByIndex = new Dictionary<int, WeakReference<object>>();
|
||||
_indexByObject = new Dictionary<WeakReference<object>, int>(new WeakReferenceComparer());
|
||||
_cleanupIndices = new List<int>();
|
||||
_lock = new object();
|
||||
|
||||
_counter = 1; // index 0 is reserved for null
|
||||
_updateOps = 0;
|
||||
}
|
||||
|
||||
public object Lookup(int index)
|
||||
{
|
||||
if (index == 0)
|
||||
return null;
|
||||
|
||||
if (_objectByIndex.TryGetValue(index, out WeakReference<object> weakRef))
|
||||
if (weakRef.TryGetTarget(out object obj))
|
||||
return obj;
|
||||
|
||||
throw new RuntimeException($"no object was found at index {index}", null);
|
||||
}
|
||||
|
||||
public int Register(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return 0;
|
||||
|
||||
WeakReference<object> weakRef = new WeakReference<object>(obj);
|
||||
if (_indexByObject.TryGetValue(weakRef, out int index))
|
||||
return index;
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
_objectByIndex.Add(_counter, weakRef);
|
||||
_indexByObject.Add(weakRef, _counter);
|
||||
|
||||
_updateOps++;
|
||||
AutoClean();
|
||||
|
||||
return _counter++;
|
||||
}
|
||||
}
|
||||
|
||||
private void AutoClean()
|
||||
{
|
||||
if (_updateOps >= _objectByIndex.Count)
|
||||
{
|
||||
_updateOps = 0;
|
||||
foreach (int key in _objectByIndex.Keys)
|
||||
{
|
||||
WeakReference<object> weakRef = _objectByIndex[key];
|
||||
if (!weakRef.TryGetTarget(out _))
|
||||
_cleanupIndices.Add(key);
|
||||
}
|
||||
|
||||
foreach (int key in _cleanupIndices)
|
||||
_objectByIndex.Remove(key);
|
||||
_cleanupIndices.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private class WeakReferenceComparer : IEqualityComparer<WeakReference<object>>
|
||||
{
|
||||
public bool Equals(WeakReference<object> x, WeakReference<object> y)
|
||||
{
|
||||
if (x.TryGetTarget(out object first))
|
||||
if (y.TryGetTarget(out object second))
|
||||
return ReferenceEquals(first, second);
|
||||
return false;
|
||||
}
|
||||
|
||||
public int GetHashCode(WeakReference<object> obj)
|
||||
=> obj.TryGetTarget(out object target) ? target.GetHashCode() : 0;
|
||||
}
|
||||
}
|
||||
}
|
179
net_ure/source/bridge/native/WeakOidTypeTable.cs
Normal file
179
net_ure/source/bridge/native/WeakOidTypeTable.cs
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace com.sun.star.uno.native
|
||||
{
|
||||
internal class WeakOidTypeTable
|
||||
{
|
||||
private readonly Dictionary<string, Level1Entry> _level1Map;
|
||||
private readonly List<(string, Type)> _cleanupEntries;
|
||||
private readonly object _lock;
|
||||
|
||||
private int _count;
|
||||
private int _updateOps;
|
||||
|
||||
public WeakOidTypeTable()
|
||||
{
|
||||
_level1Map = new Dictionary<string, Level1Entry>();
|
||||
_cleanupEntries = new List<(string, Type)>();
|
||||
_lock = new object();
|
||||
|
||||
_count = 0;
|
||||
_updateOps = 0;
|
||||
}
|
||||
|
||||
public object RegisterInterface(object obj, string oid, Type type)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
PurgeStaleEntries();
|
||||
|
||||
if (!_level1Map.ContainsKey(oid))
|
||||
_level1Map[oid] = new Level1Entry();
|
||||
|
||||
Level1Entry level1 = _level1Map[oid];
|
||||
if (level1.TryGetCompatible(type, out Level2Entry level2))
|
||||
{
|
||||
if (level2.TryGetTarget(out object o))
|
||||
{
|
||||
level2.Acquire();
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
level1[type] = new Level2Entry(obj);
|
||||
++_count;
|
||||
++_updateOps;
|
||||
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public bool RevokeInterface(string oid, Type type)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
Level2Entry level2 = null;
|
||||
|
||||
if (_level1Map.TryGetValue(oid, out Level1Entry level1))
|
||||
{
|
||||
if (level1.TryGetCompatible(type, out level2))
|
||||
{
|
||||
if (level2.Release())
|
||||
{
|
||||
level1.Remove(type);
|
||||
if (level1.Count == 0)
|
||||
_level1Map.Remove(oid);
|
||||
|
||||
--_count;
|
||||
++_updateOps;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PurgeStaleEntries();
|
||||
|
||||
return level2 != null;
|
||||
}
|
||||
}
|
||||
|
||||
public Object GetInterface(string oid, Type type)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_level1Map.TryGetValue(oid, out Level1Entry level1))
|
||||
if (level1.TryGetCompatible(type, out Level2Entry level2))
|
||||
if (level2.TryGetTarget(out object obj))
|
||||
return obj;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_level1Map.Clear();
|
||||
_updateOps = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void PurgeStaleEntries()
|
||||
{
|
||||
if (_updateOps >= _count)
|
||||
{
|
||||
_updateOps = 0;
|
||||
|
||||
foreach (string oid in _level1Map.Keys)
|
||||
{
|
||||
Level1Entry level1 = _level1Map[oid];
|
||||
foreach (Type type in level1.Keys)
|
||||
{
|
||||
Level2Entry level2 = level1[type];
|
||||
if (!level2.TryGetTarget(out _))
|
||||
{
|
||||
_cleanupEntries.Add((oid, type));
|
||||
--_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ((string oid, Type type) in _cleanupEntries)
|
||||
{
|
||||
_level1Map[oid].Remove(type);
|
||||
if (_level1Map[oid].Count == 0)
|
||||
_level1Map.Remove(oid);
|
||||
}
|
||||
_cleanupEntries.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private class Level1Entry : Dictionary<Type, Level2Entry>
|
||||
{
|
||||
public bool TryGetCompatible(Type type, out Level2Entry level2)
|
||||
{
|
||||
if (TryGetValue(type, out level2))
|
||||
return true;
|
||||
|
||||
foreach (Type stored in Keys)
|
||||
{
|
||||
if (type.IsAssignableFrom(stored))
|
||||
{
|
||||
level2 = this[stored];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
level2 = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private class Level2Entry
|
||||
{
|
||||
private readonly WeakReference<object> _ref;
|
||||
private int _count;
|
||||
|
||||
public Level2Entry(object obj)
|
||||
{
|
||||
_ref = new WeakReference<object>(obj);
|
||||
_count = 1;
|
||||
}
|
||||
|
||||
public bool TryGetTarget(out object obj) => _ref.TryGetTarget(out obj);
|
||||
|
||||
public void Acquire() => ++_count;
|
||||
public bool Release() => --_count == 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -180,6 +180,8 @@ $(eval $(call gb_Package_add_files_with_dir,odk_examples,$(SDKDIRNAME)/examples,
|
|||
DevelopersGuide/Extensions/DialogWithHelp/help/en/com.foocorp.foo-ext/subfolder/anotherpage.xhp \
|
||||
DevelopersGuide/FirstSteps/FirstUnoContact/cxx/FirstUnoContact.cxx \
|
||||
DevelopersGuide/FirstSteps/FirstUnoContact/cxx/Makefile \
|
||||
DevelopersGuide/FirstSteps/FirstUnoContact/csharp/FirstUnoContact.cs \
|
||||
DevelopersGuide/FirstSteps/FirstUnoContact/csharp/Makefile \
|
||||
DevelopersGuide/FirstSteps/FirstUnoContact/java/FirstUnoContact.java \
|
||||
DevelopersGuide/FirstSteps/FirstUnoContact/java/Makefile \
|
||||
DevelopersGuide/FirstSteps/FirstUnoContact/java/build.xml \
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
using com.sun.star.lang;
|
||||
using com.sun.star.uno;
|
||||
|
||||
try
|
||||
{
|
||||
XComponentContext xContext = NativeBootstrap.bootstrap();
|
||||
Console.WriteLine("Connected to a running office...");
|
||||
|
||||
XMultiComponentFactory xMCF = xContext.getServiceManager();
|
||||
Console.WriteLine("Remote service manager is {0}", xMCF is null ? "not available" : "available");
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch (UnoException e)
|
||||
{
|
||||
Console.Error.WriteLine(e.Message);
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
# Builds the FirstUnoContact example of the Developers Guide.
|
||||
|
||||
PRJ = ../../../../..
|
||||
SETTINGS = $(PRJ)/settings
|
||||
|
||||
include $(SETTINGS)/settings.mk
|
||||
include $(SETTINGS)/std.mk
|
||||
|
||||
# Settings
|
||||
APP_NAME = FirstUnoContact
|
||||
APP_LANG = cs
|
||||
|
||||
APP_SRC_DIR = $(subst /,$(PS),$(CURDIR))
|
||||
APP_BIN_DIR = $(subst /,$(PS),$(OUT_BIN))
|
||||
APP_MISC_DIR = $(subst /,$(PS),$(OUT_MISC)/$(APP_NAME))
|
||||
|
||||
APP_PROJ_NAME = $(APP_NAME).$(APP_LANG)proj
|
||||
APP_PROJ_FILE = $(APP_MISC_DIR)/$(APP_PROJ_NAME)
|
||||
|
||||
APP_EXE_NAME = $(APP_NAME)$(EXE_EXT)
|
||||
APP_EXE_FILE = $(APP_BIN_DIR)/$(APP_EXE_NAME)
|
||||
|
||||
DOTNET_FLAGS = -c Release
|
||||
LO_NUPKG_ID = LibreOffice.Bindings
|
||||
LO_NUPKG_VERSION = 0.1.0
|
||||
LO_NUPKG_DIR = $(abspath $(PRJ)/dotnet)
|
||||
|
||||
# Targets
|
||||
.PHONY: ALL
|
||||
ALL : $(APP_NAME)
|
||||
|
||||
include $(SETTINGS)/stdtarget.mk
|
||||
|
||||
$(APP_PROJ_FILE) :
|
||||
-$(MKDIR) $(@D)
|
||||
$(ECHO) "<Project Sdk=\"Microsoft.NET.Sdk\">" > $@
|
||||
$(ECHO) " <PropertyGroup>" >> $@
|
||||
$(ECHO) " <AssemblyName>$(APP_NAME)</AssemblyName>" >> $@
|
||||
$(ECHO) " <TargetFramework>net8.0</TargetFramework>" >> $@
|
||||
$(ECHO) " <OutputType>exe</OutputType>" >> $@
|
||||
$(ECHO) " <PublishSingleFile>true</PublishSingleFile>" >> $@
|
||||
$(ECHO) " <SelfContained>false</SelfContained>" >> $@
|
||||
$(ECHO) " <IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>" >> $@
|
||||
$(ECHO) " <RestoreAdditionalProjectSources>$(LO_NUPKG_DIR)</RestoreAdditionalProjectSources>" >> $@
|
||||
$(ECHO) " </PropertyGroup>" >> $@
|
||||
$(ECHO) " <ItemGroup>" >> $@
|
||||
$(ECHO) " <PackageReference Include=\"$(LO_NUPKG_ID)\" Version=\"$(LO_NUPKG_VERSION)\" />" >> $@
|
||||
$(ECHO) " <Compile Include=\"$(APP_SRC_DIR)/*.$(APP_LANG)\" />" >> $@
|
||||
$(ECHO) " </ItemGroup>" >> $@
|
||||
$(ECHO) "</Project>" >> $@
|
||||
$(ECHOLINE) >> $@
|
||||
|
||||
$(APP_EXE_FILE) : $(APP_PROJ_FILE)
|
||||
-$(MKDIR) $(@D)
|
||||
$(SDK_DOTNET) publish $< $(DOTNET_FLAGS) -o $(<D)
|
||||
$(COPY) $(<D)/$(APP_EXE_NAME) $@
|
||||
|
||||
.PHONY: $(APP_NAME)
|
||||
$(APP_NAME) : $(APP_EXE_FILE)
|
||||
$(ECHO) --------------------------------------------------------
|
||||
$(ECHO) Use the following commands to run the example:
|
||||
$(ECHO) $(MAKE) run OR $(MAKE) $(APP_NAME).run
|
||||
$(ECHO)
|
||||
$(ECHO) And the following commands to clean the example:
|
||||
$(ECHO) $(MAKE) clean OR $(MAKE) $(APP_NAME).clean
|
||||
$(ECHO) --------------------------------------------------------
|
||||
|
||||
.PHONY: $(APP_NAME).run run
|
||||
$(APP_NAME).run run : $(APP_EXE_FILE)
|
||||
cd $(<D) && ./$(<F)
|
||||
|
||||
.PHONY: $(APP_NAME).clean clean
|
||||
$(APP_NAME).clean clean :
|
||||
-$(DELRECURSIVE) $(APP_MISC_DIR)
|
||||
-$(DEL) $(APP_EXE_FILE)
|
Loading…
Reference in a new issue