c# - 使用 Mupen64Plus Unmanaged C dll API 命令填充 C# 结构

标签 c# c struct dll unmanaged

我正在使用 Mupen64Plus以及包含的 m64p_test_rom.v64 文件。

我正在使用 C# 与用 C 编写的 mupen64plus.dll API 对话。


问题

我正在尝试使用其 API 命令 M64CMD_ROM_GET_HEADERm64p_test_rom.v64 获取 ROM header ,其中包含 Name 等属性, 制造商 ID国家/地区代码。看起来该命令将数据存储在 struct 中。

问题是当调用 API 命令来填充 struct 时,变量保持为空,它不会用新值填充它。


应用程序接口(interface)

我正在使用这个 C# API code从 BizHawk 与 mupen64plus.dll 对话。

命令

Mupen64Plus v2.0 Core Front-End Wiki

  1. CoreDoCommand(m64p_command 命令, int ParamInt, void *ParamPtr)

    Command 枚举类型,指定应执行的命令。

    ParamInt:一个整数值,可用作命令的输入。
    ParamPtr:可用作命令输入的指针。

  2. M64CMD_ROM_GET_HEADER

    这将检索当前打开的 ROM 的 header 数据。必须打开 ROM 镜像。

    ParamInt:指向 rom_header 结构的指针接收数据
    ParamPtr:rom_header 结构的字节大小。


ROM 头结构

在我的 C# 项目中,我创建了一个新的 struct 以匹配 Mupen64Plus 的 C 源代码中的结构。我不确定我是否已将它从 C 正确地转换为 C#

Mupen64Plus C m64p_types.h

typedef struct
{
   uint8_t  init_PI_BSB_DOM1_LAT_REG;  /* 0x00 */
   uint8_t  init_PI_BSB_DOM1_PGS_REG;  /* 0x01 */
   uint8_t  init_PI_BSB_DOM1_PWD_REG;  /* 0x02 */
   uint8_t  init_PI_BSB_DOM1_PGS_REG2; /* 0x03 */
   uint32_t ClockRate;                 /* 0x04 */
   uint32_t PC;                        /* 0x08 */
   uint32_t Release;                   /* 0x0C */
   uint32_t CRC1;                      /* 0x10 */
   uint32_t CRC2;                      /* 0x14 */
   uint32_t Unknown[2];                /* 0x18 */
   uint8_t  Name[20];                  /* 0x20 */
   uint32_t unknown;                   /* 0x34 */
   uint32_t Manufacturer_ID;           /* 0x38 */
   uint16_t Cartridge_ID;              /* 0x3C - Game serial number  */
   uint16_t Country_code;              /* 0x3E */
} m64p_rom_header;

我的 C# 结构

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct m64p_rom_header
{
    public byte init_PI_BSB_DOM1_LAT_REG;  /* 0x00 */
    public byte init_PI_BSB_DOM1_PGS_REG;  /* 0x01 */
    public byte init_PI_BSB_DOM1_PWD_REG;  /* 0x02 */
    public byte init_PI_BSB_DOM1_PGS_REG2; /* 0x03 */
    public uint ClockRate;                 /* 0x04 */
    public uint PC;                        /* 0x08 */
    public uint Release;                   /* 0x0C */
    public uint CRC1;                      /* 0x10 */
    public uint CRC2;                      /* 0x14 */
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
    public uint[] Unknown;                 /* 0x18 */
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
    public byte[] Name;                    /* 0x20 */
    public uint unknown;                   /* 0x34 */
    public uint Manufacturer_ID;           /* 0x38 */
    public ushort Cartridge_ID;            /* 0x3C - Game serial number  */
    public ushort Country_code;            /* 0x3E */
};

非托管函数指针

我添加了一个新的委托(delegate)声明,因此我可以使用 API 的 CoreDoCommand() 函数和 M64CMD_ROM_GET_HEADER 命令。

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error CoreDoCommandStruct(m64p_command Command, m64p_rom_header ParamInt, ref int ParamPtr);
CoreDoCommandStruct m64pCoreDoCommandStruct;

ROM 获取头文件

我正在尝试检索 ROM 的名称。

运行 API 命令 M64CMD_ROM_GET_HEADER 应该填充 m64p_rom_header struct

Name 属性应作为 Marshallh (GPL) 的 Mupen64Plus Demo 返回。

我在 rom_header.Name 上收到错误 ArgumentNullException: Array cannot be null.

当我调用命令时,ROM 已打开并正在运行。


public m64p_rom_header rom_header;

public String ROMGetHeader()
{
    // Get size of ROM Header struct
    int size = Marshal.SizeOf(typeof(m64p_rom_header)); // returns value of 20?

    // API ROM Get Header Command
    // Question: Populates all variables in the m64p_rom_header struct?
    m64pCoreDoCommandStruct(m64p_command.M64CMD_ROM_GET_HEADER, rom_header, ref size);

    // Return the byte Array and convert to String
    return System.Text.Encoding.Default.GetString(rom_header.Name); // <-- Error: Array null
}

最佳答案

您以错误的顺序定义/传递参数给方法。委托(delegate)的第二个参数是 int 类型,第三个参数是 C 中的 void pointer 并且应用于传递数据作为引用。 例如,您可以在您发送的链接中找到以下代码(BizHawk/mupen64pluseCoreApi.cs):

// Pass the rom to the core
result = m64pCoreDoCommandByteArray(m64p_command.M64CMD_ROM_OPEN, rom.Length, rom);

所以delegate的定义应该是这样的:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate m64p_error CoreDoCommandStruct(m64p_command Command, int ParamInt, ref m64p_rom_header ParamPtr);
CoreDoCommandStruct m64pCoreDoCommandStruct;

你的使用方式应该是这样的:

m64pCoreDoCommandStruct(m64p_command.M64CMD_ROM_GET_HEADER, size, ref rom_header);

关于c# - 使用 Mupen64Plus Unmanaged C dll API 命令填充 C# 结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57603448/

相关文章:

c# - 陷入无限 if 循环

C 通过主机名获取ip

c - 当 fscanf 从文本文件读取特定值时结束循环

c - 如何修复此结构/链表脚本中的不兼容类型?

c - 奇怪的结构声明

c# - 在.Net Core 2.0中使用MVC6选择标签不显示占位符

c# - X >>= N 做什么?

c - 如何使用两个正斜杠提取字符串

c# - 类中结构字段的保护级别

c# - WebApi OData v4 ComlexType 不能有 EntityType