Reputation: 4675
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.
I'm using this C# API code from BizHawk to talk to mupen64plus.dll
.
Commands
Mupen64Plus v2.0 Core Front-End Wiki
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.
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.
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 */
};
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;
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
}
Upvotes: 3
Views: 62
Reputation: 71
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);
Upvotes: 2