Skip to content

Commit

Permalink
fixes #1324 выходные параметры в вызовах COMОбъектов
Browse files Browse the repository at this point in the history
  • Loading branch information
EvilBeaver committed Aug 8, 2023
1 parent a15435a commit e73eb68
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 12 deletions.
16 changes: 14 additions & 2 deletions src/ScriptEngine/Machine/ComReflectionNameToIdMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ This Source Code Form is subject to the terms of the
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using ScriptEngine.Machine.Contexts;

namespace ScriptEngine.Machine
{
Expand Down Expand Up @@ -70,13 +71,24 @@ public int FindMethod(object instance, string name)

try
{
return instance.GetType().InvokeMember(name,
var arrayOfArgs = callParams.Select(x => ContextValuesMarshaller.CastToCLRObject(x.GetRawValue())).ToArray();
var retValue = instance.GetType().InvokeMember(name,
BindingFlags.InvokeMethod | BindingFlags.IgnoreCase
| BindingFlags.Public | BindingFlags.OptionalParamBinding
| BindingFlags.Instance,
new ValueBinder(),
instance,
callParams.Cast<object>().ToArray());
arrayOfArgs);

for (int i = 0; i < callParams.Length; i++)
{
if (callParams[i] is IVariable variable)
{
variable.Value = ContextValuesMarshaller.ConvertReturnValue(arrayOfArgs[i]);
}
}

return retValue;
}
catch (TargetInvocationException e)
{
Expand Down
16 changes: 12 additions & 4 deletions src/ScriptEngine/Machine/Contexts/COMWrapperContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ This Source Code Form is subject to the terms of the
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace ScriptEngine.Machine.Contexts
{
Expand Down Expand Up @@ -66,7 +67,7 @@ public static COMWrapperContext Create(string progId, IValue[] arguments)
type = type.MakeGenericType(genericTypes.ToArray());
}

object instance = Activator.CreateInstance(type, MarshalArguments(arguments));
object instance = Activator.CreateInstance(type, MarshalArguments(arguments).values);

return InitByInstance(type, instance);
}
Expand Down Expand Up @@ -105,10 +106,17 @@ private static bool TypeIsRuntimeCallableWrapper(Type type)
return type.FullName == "System.__ComObject" || type.BaseType.FullName == "System.__ComObject"; // string, cause it's hidden type
}

public static object[] MarshalArguments(IValue[] arguments)
public static (object[] values, ParameterModifier flags) MarshalArguments(IValue[] arguments)
{
var args = arguments.Select(x => MarshalIValue(x)).ToArray();
return args;
var values = new object[arguments.Length];
var flags = new ParameterModifier(arguments.Length);
for (int i = 0; i < arguments.Length; i++)
{
values[i] = MarshalIValue(arguments[i]);
flags[i] = arguments[i] is IVariable;
}

return (values, flags);
}

public static object MarshalIValue(IValue val)
Expand Down
21 changes: 19 additions & 2 deletions src/ScriptEngine/Machine/Contexts/UnmanagedCOMWrapperContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ This Source Code Form is subject to the terms of the
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using ScriptEngine.Machine.Rcw;

namespace ScriptEngine.Machine.Contexts
Expand Down Expand Up @@ -191,7 +192,9 @@ public override void CallAsProcedure(int methodNumber, IValue[] arguments)
{
try
{
DispatchUtility.Invoke(Instance, dispId, MarshalArguments(arguments));
var argsData = MarshalArguments(arguments);
DispatchUtility.Invoke(Instance, dispId, argsData.values, new [] { argsData.flags });
RemapOutputParams(arguments, argsData.values, argsData.flags);
}
catch (System.Reflection.TargetInvocationException e)
{
Expand All @@ -217,7 +220,9 @@ public override void CallAsFunction(int methodNumber, IValue[] arguments, out IV
{
try
{
var result = DispatchUtility.Invoke(Instance, dispId, MarshalArguments(arguments));
var argsData = MarshalArguments(arguments);
var result = DispatchUtility.Invoke(Instance, dispId, argsData.values, new [] { argsData.flags });
RemapOutputParams(arguments, argsData.values, argsData.flags);
retValue = CreateIValue(result);
}
catch (System.Reflection.TargetInvocationException e)
Expand All @@ -230,6 +235,18 @@ public override void CallAsFunction(int methodNumber, IValue[] arguments, out IV
throw RuntimeException.MethodNotFoundException(method.Name);
}
}

private void RemapOutputParams(IValue[] arguments, object[] values, ParameterModifier flags)
{
for (int i = 0; i < arguments.Length; i++)
{
if (flags[i])
{
var variable = (IVariable)arguments[i];
variable.Value = CreateIValue(values[i]);
}
}
}

private bool TryFindMethod(string name, out RcwMethodMetadata md)
{
Expand Down
2 changes: 1 addition & 1 deletion src/ScriptEngine/Machine/MachineInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1116,7 +1116,7 @@ private void PrepareContextCallArguments(int arg, out IRuntimeContextInstance co
var argValue = factArgs[i];
if (argValue.DataType != DataType.NotAValidValue)
{
argValues[i] = argValue.GetRawValue();
argValues[i] = argValue;
}
}
}
Expand Down
24 changes: 21 additions & 3 deletions src/ScriptEngine/Machine/Rcw/DispatchUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,27 @@ public static bool TryGetDispId(object obj, string name, out int dispId)
/// This can invoke a method or a property get accessor.
/// </remarks>
public static object Invoke(object obj, int dispId, object[] args)
{
object result = Invoke(obj, dispId, args, null);
return result;
}

/// <summary>
/// Invokes a member by DISPID.
/// </summary>
/// <param name="obj">An object that implements IDispatch.</param>
/// <param name="dispId">The DISPID of a member. This can be obtained using
/// <see cref="TryGetDispId(object, string, out int)"/>.</param>
/// <param name="args">The arguments to pass to the member.</param>
/// <param name="modifiers">ByRef modifiers</param>
/// <returns>The member's return value.</returns>
/// <remarks>
/// This can invoke a method or a property get accessor.
/// </remarks>
public static object Invoke(object obj, int dispId, object[] args, ParameterModifier[] modifiers)
{
string memberName = "[DispId=" + dispId + "]";
object result = Invoke(obj, memberName, args);
object result = Invoke(obj, memberName, args, modifiers);
return result;
}

Expand All @@ -119,12 +137,12 @@ public static object Invoke(object obj, int dispId, object[] args)
/// <remarks>
/// This can invoke a method or a property get accessor.
/// </remarks>
public static object Invoke(object obj, string memberName, object[] args)
public static object Invoke(object obj, string memberName, object[] args, ParameterModifier[] modifiers)
{
RequireReference(obj, "obj");
Type type = obj.GetType();
object result = type.InvokeMember(memberName, BindingFlags.InvokeMethod | BindingFlags.GetProperty,
null, obj, args, null);
null, obj, args, modifiers, null, null);
return result;
}

Expand Down

0 comments on commit e73eb68

Please sign in to comment.