从C# DLL创建一个VBA用户定义对象的数组

5

背景信息:
我正在构建一个基于VBA运行的SCADA系统,但我需要一些C#的功能。我使用C#构建了一个DLL库,并成功实现了DLL与VBA之间的数据传输。

[ComVisible(true), ClassInterface(ClassInterfaceType.AutoDual)]
public class BE_Log
{
    public string DateTime
    {
        [return: MarshalAs(UnmanagedType.BStr)]
        get;
        [param: MarshalAs(UnmanagedType.BStr)]
        set;
    }
    public string User
    {
        [return: MarshalAs(UnmanagedType.BStr)]
        get;
        [param: MarshalAs(UnmanagedType.BStr)]
        set;
    }
    public string SCADA
    {
        [return: MarshalAs(UnmanagedType.BStr)]
        get;
        [param: MarshalAs(UnmanagedType.BStr)]
        set;
    }
    public string Tag
    {
        [return: MarshalAs(UnmanagedType.BStr)]
        get;
        [param: MarshalAs(UnmanagedType.BStr)]
        set;
    }
    public string Area1
    {
        [return: MarshalAs(UnmanagedType.BStr)]
        get;
        [param: MarshalAs(UnmanagedType.BStr)]
        set;
    }
    public string Area2
    {
        [return: MarshalAs(UnmanagedType.BStr)]
        get;
        [param: MarshalAs(UnmanagedType.BStr)]
        set;
    }
    public string Description
    {
        [return: MarshalAs(UnmanagedType.BStr)]
        get;
        [param: MarshalAs(UnmanagedType.BStr)]
        set;
    }
    public string ValueOld
    {
        [return: MarshalAs(UnmanagedType.BStr)]
        get;
        [param: MarshalAs(UnmanagedType.BStr)]
        set;
    }
    public string ValueNew
    {
        [return: MarshalAs(UnmanagedType.BStr)]
        get;
        [param: MarshalAs(UnmanagedType.BStr)]
        set;
    }

    public BE_Log(string DataTime, string User, string SCADA, string Tag, string Area1, string Area2,string Description)
    {
        this.DateTime = DateTime;
        this.User = User;
        this.SCADA = SCADA;
        this.Tag = Tag;
        this.Area1 = Area1;
        this.Area2 = Area2;
        this.Description = Description;
    }

    public BE_Log(string DataTime, string User, string SCADA, string Tag, string Area1, string Area2, string Description, string ValueOld, string ValueNew)
    {
        this.DateTime = DateTime;
        this.User = User;
        this.SCADA = SCADA;
        this.Tag = Tag;
        this.Area1 = Area1;
        this.Area2 = Area2;
        this.Description = Description;
        this.ValueOld = ValueOld;
        this.ValueNew = ValueNew;
    }

}

我把这个类返回了,代码如下:
[ComVisible(true), ClassInterface(ClassInterfaceType.AutoDual)]
public class TI
{
    private BLL_LogBook bll;

    public TI()
    {
        bll = new BLL_LogBook();
    }

    [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_USERDEFINED)]  //  SafeArrayUserDefinedSubType = typeof(BE_Log)
    public BE_Log[] CreateLogBook()
    {
        List<BE_Log> logs = bll.GetLogEntry();
        return logs.ToArray();
    }
}

我的数据层:
public class BLL_LogBook
{
    public List<BE_Log> GetLogEntry()
    {
        List<BE_Log> logs = new List<BE_Log>();
        logs.Add(new BE_Log("05-05-2015", "some user", "scada01", "LA010NDA10CU12XQ12", "Ribe", "Esbjerg", "Some short description"));
        logs.Add(new BE_Log("06-05-2015", "test user", "scada01", "LA010NDA10CU12XB05", "Herning", "KBH", "Some long description"));
        logs.Add(new BE_Log("07-05-2015", "normal user", "scada02", "LA010NDA10CU12YQ01", "Åhus", "Tønder", "Some test description"));

        return logs;
    }
}

被调用的静态方法是VBA:

static class UnmanagedExports
{
    [DllExport]
    [return: MarshalAs(UnmanagedType.IDispatch)]
    static Object TI_Object()
    {
        return new TI();
    }
}

在VBA中,我使用以下方法获取数据:
Declare Function TI_Object Lib "<path>\\TJI.dll" () As Object

Sub TestTheTestClass()
    Dim TJI As Object
    Set TJI = TI_Object()

    Dim test As Variant
    test = TJI.CreateLogBook()

    Dim log As Variant
    Set log = test(0)

    Debug.Print log.User
End Sub

现在来到我的问题:
如何返回类“BE_Log”的数组列表
编辑: 这就是我卡住的地方:http://puu.sh/hnPGe/472ff863d0.png 我一直在尝试阅读微软的一些文档,但没有太多的成功。
我最初遵循的指南是这个:
http://www.analystcave.com/excel-use-c-sharp-in-excel-vba/ 他说了以下内容,但我并不完全理解它:

如果您使用数组作为参数,请确保使用C#“ref”按引用获取选项,例如ref int[] ar

我认为这与“MarshalAs”或我在VBA中读取数据的方式有关。
1个回答

1

如果您正在使用数组作为参数,请确保使用C#的“ref”按引用获取选项,例如ref int[] ar

这是正确的,但您没有任何接受数组参数的方法,因此它不适用于您的情况。

您尝试过更改方法签名吗:

public Log CreateLogBook()

转换为返回数组的签名:

public Log[] CreateLogBook()

我无法让VBA读取数据,或者可能我没有正确执行“Marshal”操作? 您能否提供一个示例,说明如何从DLL中在VBA中读取数组? - Rasmus Plats
@RasmusPlats - 当您尝试调用该方法时会发生什么?您是否收到异常(VBA运行时错误),如果是,那么是什么错误消息?您是否收到了一些意外的返回值,在这种情况下,请使用VBA调试器进行检查。 - Joe
我遇到了运行时错误 '424' (需要对象) Dim test As Object Set test = DLL.CreateLogBook() - Rasmus Plats
1
你的截图显示了类型为BE_Log的test(0)test(1)的"<No Variables>"。如果BE_Log是一个集合类型,并且集合为空,我会期望看到这种情况。此外,你正在访问log.DateTime,这不是你发布的Log类的有效属性。如果你发布一个完整、一致的示例,将会更有帮助-请参阅http://stackoverflow.com/help/mcve。 - Joe
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Rasmus Plats
显示剩余9条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接