0

我试图以这样的方式 P/invoke 这个我应该能够从 C# 访问这个结构的 const char* 成员(系统、游戏、歌曲、版权等)。

这是在 C++ 标头中定义的结构:gme.h从第 79 行开始

struct gme_info_t
{
    /* times in milliseconds; -1 if unknown */
    int length;         /* total length, if file specifies it */
    int intro_length;   /* length of song up to looping section */
    int loop_length;    /* length of looping section */

    /* Length if available, otherwise intro_length+loop_length*2 if available,
    otherwise a default of 150000 (2.5 minutes). */
    int play_length;

    int i4,i5,i6,i7,i8,i9,i10,i11,i12,i13,i14,i15; /* reserved */

    /* empty string ("") if not available */
    const char* system;
    const char* game;
    const char* song;
    const char* author;
    const char* copyright;
    const char* comment;
    const char* dumper;

    const char *s7,*s8,*s9,*s10,*s11,*s12,*s13,*s14,*s15; /* reserved */
};

在我的 C# 代码中,我对这个结构进行了如下建模:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct gme_info_t
{
    public int length;
    public int introLength;
    public int loopLength;
    public int playLength;

    public int i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15;

    public string system;
    public string game;
    public string song;
    public string author;
    public string copyright;
    public string comment;
    public string dumper;

    public string s7, s8, s9, s10, s11, s12, s13, s14, s15;
}

现在,我正在调用的函数是我已 P/Invoked 的函数,其 C++ 原型如下:

gme_err_t gme_track_info( Music_Emu const* me, gme_info_t** out, int track )

哪里gme_err_tconst char*

(如果您想直接查看,请参见 gme.h,第 74 行)

(参见gme.cpp,第 252 行的定义)

因此,没有其所有 typedef 的函数如下:

const char* gme_track_info( Music_Emu const* me, gme_info_t** out, int track )

此函数的工作方式是,当使用有效的 Music_Emu 和有效曲目调用时,结果是分配给参数“out”的有关音乐曲目的信息。

返回的 const char* 基本上是用于发生错误时,所以它不是主要焦点。'out' 参数是。

我在 C# 中为此函数定义了 P/Invoke,如下所示:

[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern string gme_track_info(IntPtr emuHandle, out gme_info_t trackInfo, int track);

这是我目前尝试读取该结构中的版权字符串的代码。

static void Main()
{

    // Initialize the MusicEmu reference first (this works fine).
    IntPtr emuRef;
    string initEmuRef = NativeMethods.gme_open_file("Adventure Island 4.nsf", out emuRef, 48000);
    Console.WriteLine("Error Message (if any): " + initEmuRef);

    // Now get the track info.
    gme_info_t trackInfo;
    NativeMethods.gme_track_info(emuRef, out trackInfo, 0);
    Console.WriteLine("Copyright: " + trackInfo.copyright); // I get an empty string. When checked with a different NSF reader it prints "1994 Hudson Soft."

    // Keep console window up.
    Console.ReadLine();
}

任何帮助,将不胜感激。我已经尝试了大约 4 个小时来完成这项工作。我已经在 StackOverflow(以及整个网络)中寻找可能的解决方案,但我没有找到任何接近此类问题的解决方案。大多数其他问题是关于指向数组结构的指针的指针等,这对于这种情况根本没有多大帮助。

如果需要任何其他信息,请问,我很乐意提供。

4

1 回答 1

0

你的trackInfo参数应该是一个out IntPtr. 然后,您可以使用该方法将其编组为 C# 结构Marshal.PtrToStructure

IntPtr trackInfoPtr;
NativeMethods.gme_track_info(emuRef, out trackInfoPtr);
gme_info_t trackInfo = (gme_info_t)Marshal.PtrToStructure(trackInfoPtr, typeof(gme_info_t));
于 2013-05-31T22:38:26.433 回答