COM Interop:C#DLL导致Excel崩溃("预期:To")

时间:2014-06-21 22:22:52

标签: c# vba dll com-interop

我想了解更多有关Runtime.InteropServices的信息。为此,我决定为Excel创建一个基本游戏,它是从C#DLL运行的。以下是游戏的顶级C#代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace ExcelEscapeGame
{

    [Guid("F4810BC6-C65E-4D1B-855A-D645C7F66893")]
    [ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface IEscapeGame
    {
        [DispId(1)]
        void NewGame([param: MarshalAs(UnmanagedType.I1)] byte EnemyMoveSpeed,
            [param: MarshalAs(UnmanagedType.I1)] byte PlayerMoveSpeed,
            [param: MarshalAs(UnmanagedType.I1)] byte EnemyCount,
            [param: MarshalAs(UnmanagedType.I4)] int OuterWidth,
            [param: MarshalAs(UnmanagedType.I4)] int OuterLength,
            [param: MarshalAs(UnmanagedType.I4)] int BorderWidth);

        [DispId(2)]
        [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_I4)]
        int[,] GameMap();
    }

    [Guid("B937DE85-776F-4822-A3B7-A936F2043537")]
    [ComVisible(true), ClassInterface(ClassInterfaceType.None)]
    public class EscapeGame : IEscapeGame
    {
        private GameFrame GF;
        private EnemyFlock TheHorde;
        private Player player;
        private int[,] BaseMap;
        private bool Initialized = false;

        public void NewGame(byte EnemyMoveSpeed, byte PlayerMoveSpeed, byte EnemyCount,
            int OuterWidth, int OuterLength, int BorderWidth)
        {
            GF = new GameFrame(new Point(0, 0), new Point(BorderWidth, BorderWidth), OuterLength, OuterWidth);
            TheHorde = new EnemyFlock(EnemyCount, EnemyMoveSpeed);
            TheHorde.RandomlyPositionAtEdge(GF);
            player = new Player(PlayerMoveSpeed, GF.CentrePoint());
            BaseMap = GF.FrameMap();
            Initialized = true;
        }

        public EscapeGame() { }

        public EscapeGame(byte EnemyMoveSpeed, byte PlayerMoveSpeed, byte EnemyCount,
            int OuterWidth, int OuterLength, int BorderWidth)
        {
            this.NewGame(EnemyMoveSpeed, PlayerMoveSpeed, EnemyCount,
            OuterWidth, OuterLength, BorderWidth);
        }

        public int[,] GameMap()
        {
            TestInitialized();
            int[,] map = CopyMap();
            Point[] EnemyPositions = TheHorde.Positions();
            foreach (Point p in EnemyPositions)
            {
                map[p.x, p.y] = (int)ColourEnum.ENEMY;
            }
            map[player.Position.x, player.Position.y] = (int)ColourEnum.PLAYER;
            return map;
        }

        private int[,] CopyMap()
        {
            TestInitialized(); 
            int[,] OutMap = new int[BaseMap.GetUpperBound(0) + 1, BaseMap.GetUpperBound(1) + 1];
            for (int i = 0; i <= BaseMap.GetUpperBound(0); i++)
            {
                for (int j = 0; j <= BaseMap.GetUpperBound(1); j++)
                {
                    OutMap[i, j] = BaseMap[i, j];
                }
            }

            return OutMap;
        }

        private void TestInitialized()
        {
            if (!Initialized) throw new NullReferenceException("The class was not initialized");
        }

    }
}

我想从Excel调用它。当我最初测试时,一切似乎都很好。现在我已经为DLL添加了更多的类(包括上面的EscapeGame类),似乎已经破坏了,我看不出原因。以下两个VBA子中的第一个(Test)曾经运行良好,现在只是导致Excel立即崩溃(没有错误消息),第二个(Go)只是给出了“预期:到”作为错误消息并且不会开始运行(辅助函数只是在它们相关的情况下):

Sub Test()

Dim point As New ExcelGames.point

point.MakePoint 10, 10
Set p.Position = point

p.MoveSpeed = 2

Dim arr As Variant, pRange As Excel.Range

arr = p.Paths

Set pRange = Sheet1.Range("f10")

Application.ScreenUpdating = False
For i = 0 To UBound(arr, 1)
    pRange.Offset(arr(i, 0), arr(i, 1)).Interior.ColorIndex = 5
Next i
Application.ScreenUpdating = True


End Sub


Sub Go()

Dim TheGame As New EscapeGame, p1 As New ExcelGames.point, offsetp As New ExcelGames.point

p1.MakePoint 0, 0
offsetp.MakePoint 2, 2

TheGame.NewGame 2, 2, 10, 20, 20, 2

Dim arr As Variant

arr = TheGame.GameMap()


Dim i As Long, j As Long

Application.ScreenUpdating = False
For i = 0 To UBound(arr, 1)
    For j = 0 To UBound(arr, 2)
        Sheet1.Cells(i + 1, j + 1).Value = arr(i, j)
    Next j
Next i
Application.ScreenUpdating = True

Dim gameRange As Excel.Range

Set gameRange = Sheet1.Range(Cells(1, 1), Cells(UBound(arr, 1) + 1, UBound(arr, 2) + 1))

FormatRange gameRange
FormatConditionRange gameRange, "=" & ExcelGames.ColourEnum_INNERSQUARE, 14395790
FormatConditionRange gameRange, "=" & ExcelGames.ColourEnum_OUTERSQUARE, 15652797
FormatConditionRange gameRange, "=" & ExcelGames.ColourEnum_PLAYER, 5296274
FormatConditionRange gameRange, "=" & ExcelGames.ColourEnum_ENEMY, 8696052

End Sub

Private Sub FormatRange(ByRef xlrange As Excel.Range)

With xlrange
    .Columns.ColumnWidth = _
    .Columns("A").ColumnWidth / .Columns("A").Width * _
    .Rows(1).Height
End With

End Sub

Private Sub FormatConditionRange(ByRef xlrange As Excel.Range, ByVal Formula As String, _
    ByVal Colour As Long)

Dim FC As FormatCondition

With xlrange
    Set FC = .FormatConditions.Add(xlCellValue, Operator:=xlEqual, Formula1:=Formula)
    With FC
        .Interior.Color = Colour
        .Font.Color = Colour
        .StopIfTrue = False
    End With
End With

End Sub

两个潜艇在执行第一行之前都会失败 - 单步执行VBIDE中的代码,无助于突出显示错误原因。当我在C#控制台应用程序中使用DLL中的类时一切正常 - 完全没有错误。 “预期:到”是什么意思,任何人都可以建议我做错了什么?

1 个答案:

答案 0 :(得分:0)

解决方案是命名第二个子“Go”导致Excel认为它期待GoTo语句。这似乎影响了该模块中的所有代码。一旦我将名称更改为“GoWork”,子代码就会正确执行。