简体   繁体   中英

Populate C# struct using Mupen64Plus Unmanaged C dll API command

I'm using Mupen64Plus and the included m64p_test_rom.v64 file.

I'm using C# to talk to the mupen64plus.dll API which is written in C .


Problem

I'm trying to use its API command M64CMD_ROM_GET_HEADER to get the ROM Header from m64p_test_rom.v64 , which contains properties like Name , Manufacturer ID , Country code . It looks like the command stores the data in a struct .

The problem is that when the API command is called to populate the struct , the variables remain null, it does not populate it with new values.


API

I'm using this C# API code from BizHawk to talk to mupen64plus.dll .

Commands

Mupen64Plus v2.0 Core Front-End Wiki

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

    Command Enumerated type specifying which command should be executed.

    ParamInt: An integer value which may be used as an input to the command.
    ParamPtr: A pointer which may be used as an input to the command.

  2. M64CMD_ROM_GET_HEADER

    This will retrieve the header data of the currently open ROM. A ROM image must be open.

    ParamInt: Pointer to a rom_header struct to receive the data .
    ParamPtr: The size in bytes of the rom_header struct.


ROM Header struct

In my C# project I created a new struct to match the one in the Mupen64Plus's C source code. I'm not sure if I have converted it from C to C# correctly.

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;

My C# struct

[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 */
};

Unmanaged Function Pointer

I've added a new delegate declaration so I can use the API's CoreDoCommand() function and M64CMD_ROM_GET_HEADER command.

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

ROM Get Header

I'm trying to retrieve the ROM's Name.

Running the API command M64CMD_ROM_GET_HEADER should populate the m64p_rom_header struct .

The Name poperty should return as Mupen64Plus Demo by Marshallh (GPL) .

I get the error ArgumentNullException: Array cannot be null. on rom_header.Name .

The ROM is open and running when i call the command.


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
}

You have defined/passed the parameters to the method in the wrong order. The second parameter of the delegate is of type int and the third parameter is a void pointer in C and should be used to pass data as a reference. For example, you can find the following code in the link you sent (BizHawk/mupen64pluseCoreApi.cs) :

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

So the definition of the delegate should be as the following:

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

and the way you use it should be as the following:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM