Return 从 C# COM 库到 VBA 的数组
Return Array from C# COM Library to VBA
我花了很多时间试图找到解决方案,但我似乎无法让它发挥作用。情况如下:
我正在设置一个供 vba 宏使用的 c# com 库。有问题的 c# 库方法将两个数组作为参数, returns 一个大小和类型与第一个参数相同的数组。这是 c# 代码(接口和实现):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Windows.Forms;
namespace Aufbereiten.Base.Controller
{
[Guid("A341A58B-96CA-42B8-8256-B8AC16586176")]
public interface IExposer
{
[DispId(1)]
void Connect(String macroName, String inputFileName, String functionType);
[DispId(2)]
Boolean Run();
[DispId(3)]
object[] StringCleaner(object lineOut, object headerOut);
}
[Guid("C66FF152-60E2-4AF3-9D65-655C224A241E")]
[Serializable(), ClassInterface(ClassInterfaceType.None), ComVisible(true)]
public class Library : IExposer
{
#region Fields
private MainController _mc;
#endregion
#region Properties
public MainController MC
{
get { return _mc; }
set { _mc = value; }
}
#endregion
#region Methods
public void Connect(String macroName, String fileName, String functionType)
{
MC = new MainController(macroName, fileName, functionType);
}
public Boolean Run()
{
return MC.Run();
}
/// <summary>
/// Cleans input string of unwanted characters
/// </summary>
/// <param name="lineOut">String Array</param>
/// <param name="headerOut">Integer Array</param>
/// <returns>String array</returns>
public object[] StringCleaner(object lineOut, object headerOut)
{
// Convert input objects to List and convert return List to string array directly
return MC.Generic.StringCleaner(ComObjectToStringList(lineOut), ComObjectToIntList(headerOut)).ToArray<string>();
}
/// <susgbomary>
/// Converts a com object into a string list
/// </summary>
/// <param name="comObj">object</param>
/// <returns>String list</returns>
private List<string> ComObjectToStringList(object comObj)
{
List<string> result = new List<string>();
// Convert COM object (VBA array) to string list
Type comObjType = comObj.GetType();
object[] args = new object[1];
int numEntries = (int)comObjType.InvokeMember("Length", BindingFlags.GetProperty, null, comObj, null);
for (int i = 0; i < numEntries; i++)
{
args[0] = i;
string currentEntry = (string)comObjType.InvokeMember("GetValue", BindingFlags.InvokeMethod, null, comObj, args);
if (currentEntry == null)
{
result.Add("");
}
else
{
result.Add(currentEntry);
}
}
return result;
}
/// <summary>
/// Converts a com object into an int list
/// </summary>
/// <param name="comObj">object</param>
/// <returns>Int32 list</returns>
private List<int> ComObjectToIntList(object comObj)
{
List<int> result = new List<int>();
// Convert COM object (VBA array) to int list
Type comObjType = comObj.GetType();
object[] args = new object[1];
int numEntries = (int)comObjType.InvokeMember("Length", BindingFlags.GetProperty, null, comObj, null);
for (int i = 0; i < numEntries; i++)
{
args[0] = i;
result.Add((int)comObjType.InvokeMember("GetValue", BindingFlags.InvokeMethod, null, comObj, args));
}
return result;
}
#endregion
}
}
Generic.StringCleaner 方法将执行清除不需要字符的参数数组 "lineOut" 的实际工作。以下是调用库方法的 VBA 代码的摘录:
Dim arrLineOut() As Variant
Dim dicInToOut As New Scripting.Dictionary
...
Dim lib As New Aufbereiten.library
lib.Connect ThisWorkbook.Name, "_Library_Test_custFile.xlsx", "CustImport"
arrLineOut = lib.StringCleaner(arrLineOut, dicInToOut.Items)
c#中的所有操作运行完美无缺,除了返回结果,清理数组。
当我 运行 宏时,我得到一个
runtime error 80131533: A mismatch has occurred between the runtime type of the array and the sub type recorded in the metadata.
谁能告诉我我做错了什么?
根据@Meehow 的建议我已经调整了
public object[] StringCleaner(object lineOut, object headerOut)
至
public string[] StringCleaner(object lineOut, object headerOut)
和
return MC.Generic.StringCleaner(ComObjectToStringList(lineOut), ComObjectToIntList(headerOut)).ToArray<string>();
至
return MC.Generic.StringCleaner(ComObjectToStringList(lineOut), ComObjectToIntList(headerOut)).ToArray();
进行这些更改后,我能够将 c# 库中的 return 值分配给 VBA 中新声明的变体数组:
Dim tmp As Variant
tmp = lib.StringCleaner(arrLineOut, dicInToOut.Items)
我花了很多时间试图找到解决方案,但我似乎无法让它发挥作用。情况如下:
我正在设置一个供 vba 宏使用的 c# com 库。有问题的 c# 库方法将两个数组作为参数, returns 一个大小和类型与第一个参数相同的数组。这是 c# 代码(接口和实现):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Windows.Forms;
namespace Aufbereiten.Base.Controller
{
[Guid("A341A58B-96CA-42B8-8256-B8AC16586176")]
public interface IExposer
{
[DispId(1)]
void Connect(String macroName, String inputFileName, String functionType);
[DispId(2)]
Boolean Run();
[DispId(3)]
object[] StringCleaner(object lineOut, object headerOut);
}
[Guid("C66FF152-60E2-4AF3-9D65-655C224A241E")]
[Serializable(), ClassInterface(ClassInterfaceType.None), ComVisible(true)]
public class Library : IExposer
{
#region Fields
private MainController _mc;
#endregion
#region Properties
public MainController MC
{
get { return _mc; }
set { _mc = value; }
}
#endregion
#region Methods
public void Connect(String macroName, String fileName, String functionType)
{
MC = new MainController(macroName, fileName, functionType);
}
public Boolean Run()
{
return MC.Run();
}
/// <summary>
/// Cleans input string of unwanted characters
/// </summary>
/// <param name="lineOut">String Array</param>
/// <param name="headerOut">Integer Array</param>
/// <returns>String array</returns>
public object[] StringCleaner(object lineOut, object headerOut)
{
// Convert input objects to List and convert return List to string array directly
return MC.Generic.StringCleaner(ComObjectToStringList(lineOut), ComObjectToIntList(headerOut)).ToArray<string>();
}
/// <susgbomary>
/// Converts a com object into a string list
/// </summary>
/// <param name="comObj">object</param>
/// <returns>String list</returns>
private List<string> ComObjectToStringList(object comObj)
{
List<string> result = new List<string>();
// Convert COM object (VBA array) to string list
Type comObjType = comObj.GetType();
object[] args = new object[1];
int numEntries = (int)comObjType.InvokeMember("Length", BindingFlags.GetProperty, null, comObj, null);
for (int i = 0; i < numEntries; i++)
{
args[0] = i;
string currentEntry = (string)comObjType.InvokeMember("GetValue", BindingFlags.InvokeMethod, null, comObj, args);
if (currentEntry == null)
{
result.Add("");
}
else
{
result.Add(currentEntry);
}
}
return result;
}
/// <summary>
/// Converts a com object into an int list
/// </summary>
/// <param name="comObj">object</param>
/// <returns>Int32 list</returns>
private List<int> ComObjectToIntList(object comObj)
{
List<int> result = new List<int>();
// Convert COM object (VBA array) to int list
Type comObjType = comObj.GetType();
object[] args = new object[1];
int numEntries = (int)comObjType.InvokeMember("Length", BindingFlags.GetProperty, null, comObj, null);
for (int i = 0; i < numEntries; i++)
{
args[0] = i;
result.Add((int)comObjType.InvokeMember("GetValue", BindingFlags.InvokeMethod, null, comObj, args));
}
return result;
}
#endregion
}
}
Generic.StringCleaner 方法将执行清除不需要字符的参数数组 "lineOut" 的实际工作。以下是调用库方法的 VBA 代码的摘录:
Dim arrLineOut() As Variant
Dim dicInToOut As New Scripting.Dictionary
...
Dim lib As New Aufbereiten.library
lib.Connect ThisWorkbook.Name, "_Library_Test_custFile.xlsx", "CustImport"
arrLineOut = lib.StringCleaner(arrLineOut, dicInToOut.Items)
c#中的所有操作运行完美无缺,除了返回结果,清理数组。
当我 运行 宏时,我得到一个
runtime error 80131533: A mismatch has occurred between the runtime type of the array and the sub type recorded in the metadata.
谁能告诉我我做错了什么?
根据@Meehow 的建议我已经调整了
public object[] StringCleaner(object lineOut, object headerOut)
至
public string[] StringCleaner(object lineOut, object headerOut)
和
return MC.Generic.StringCleaner(ComObjectToStringList(lineOut), ComObjectToIntList(headerOut)).ToArray<string>();
至
return MC.Generic.StringCleaner(ComObjectToStringList(lineOut), ComObjectToIntList(headerOut)).ToArray();
进行这些更改后,我能够将 c# 库中的 return 值分配给 VBA 中新声明的变体数组:
Dim tmp As Variant
tmp = lib.StringCleaner(arrLineOut, dicInToOut.Items)