在将 C 结构与 C# 代码联合封送时获取垃圾数据

本文关键字:获取 数据 结构 代码 在将 | 更新日期: 2023-09-27 18:31:06

我正在尝试在托管应用程序中使用以下 C 结构

typedef struct libvlc_media_track_t
{
    uint32_t    i_codec;
    uint32_t    i_original_fourcc;
    int         i_id;
    libvlc_track_type_t i_type;
    int         i_profile;
    int         i_level;
    union {
        libvlc_audio_track_t *audio;
        libvlc_video_track_t *video;
        libvlc_subtitle_track_t *subtitle;
    };
    unsigned int i_bitrate;
    char *psz_language;
    char *psz_description;
} libvlc_media_track_t;
typedef struct libvlc_audio_track_t
    {
        unsigned    i_channels;
        unsigned    i_rate;
    } libvlc_audio_track_t;
    typedef struct libvlc_video_track_t
    {
        unsigned    i_height;
        unsigned    i_width;
        unsigned    i_sar_num;
        unsigned    i_sar_den;
        unsigned    i_frame_rate_num;
        unsigned    i_frame_rate_den;
    } libvlc_video_track_t;
    typedef struct libvlc_subtitle_track_t
    {
        char *psz_encoding;
    } libvlc_subtitle_track_t;
unsigned libvlc_media_tracks_get( libvlc_media_t *p_md, libvlc_media_track_t ***tracks );

.NET 版本如下所示:

[StructLayout(LayoutKind.Explicit)]
public struct libvlc_media_track_t
{
    [FieldOffset(0)]
    public uint i_codec;
    [FieldOffset(4)]
    public uint i_original_fourcc;
    [FieldOffset(8)]
    public int i_id;
    [FieldOffset(12)]
    public libvlc_track_type_t i_type;
    [FieldOffset(16)]
    public int i_profile;
    [FieldOffset(20)]
    public int i_level;
    [FieldOffset(24)]
    public libvlc_audio_track_t audio;
    [FieldOffset(24)]
    public libvlc_video_track_t video;
    [FieldOffset(24)]
    public libvlc_subtitle_track_t subtitle;
    [FieldOffset(48)]
    public uint i_bitrate;
    [FieldOffset(52)]
    public IntPtr psz_language;
    [FieldOffset(56)]
    public IntPtr psz_description;
}
[StructLayout(LayoutKind.Sequential)]
public struct libvlc_audio_track_t
{
    public uint i_channels;
    public uint i_rate;
}
[StructLayout(LayoutKind.Sequential)]
public struct libvlc_video_track_t
{
    public uint i_height;
    public uint i_width;
    public uint i_sar_num;
    public uint i_sar_den;
    public uint i_frame_rate_num;
    public uint i_frame_rate_den;
}
[StructLayout(LayoutKind.Sequential)]
public struct libvlc_subtitle_track_t
{
    public IntPtr psz_encoding;
}
[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern int libvlc_media_tracks_get(IntPtr media, libvlc_media_track_t*** ppTracks);
unsafe
{
     libvlc_media_track_t** ppTracks;
     int num = LibVlcMethods.libvlc_media_tracks_get(m_hMedia, &ppTracks);
     if (num == 0 || ppTracks == null)
     {
         throw new Exception();
     }
     for (int i = 0; i < num; i++)
     {
         libvlc_media_track_t* pTrackInfo = ppTracks[i];            
     }
     LibVlcMethods.libvlc_media_tracks_release(ppTracks, num);
}

该代码没有任何例外地工作,但我在大多数结构/联合字段中都得到了垃圾数据。

请指教,提前致谢

编辑:我也尝试了以下内容,但它有相同的结果

[StructLayout(LayoutKind.Sequential)]
    public struct libvlc_media_track_t
    {
        public uint i_codec;
        public uint i_original_fourcc;
        public int i_id;
        public libvlc_track_type_t i_type;
        public int i_profile;
        public int i_level;
        public MediaVariant media;
        public uint i_bitrate;
        public IntPtr psz_language;
        public IntPtr psz_description;
    }
[StructLayout(LayoutKind.Explicit)]
public struct MediaVariant
{
    [FieldOffset(0)]
    public libvlc_audio_track_t audio;
    [FieldOffset(0)]
    public libvlc_video_track_t video;
    [FieldOffset(0)]
    public libvlc_subtitle_track_t subtitle;
}

在将 C 结构与 C# 代码联合封送时获取垃圾数据

你翻译了错误的联合。我怀疑当你说:

我在大多数结构/联合字段中获得垃圾数据。

你的意思是,数据在工会

之前很好,在工会之后是垃圾。让我们来看看工会。是的:

union {
    libvlc_audio_track_t *audio;
    libvlc_video_track_t *video;
    libvlc_subtitle_track_t *subtitle;
};

联合包含指针。但是您已经通过将结构放在联合中来翻译它。您的 C# 翻译等效于:

union {
    libvlc_audio_track_t audio;
    libvlc_video_track_t video;
    libvlc_subtitle_track_t subtitle;
};

所以,简单地用IntPtr代替工会,你就会很好。

[StructLayout(LayoutKind.Sequential)]
public struct libvlc_media_track_t
{
    public uint i_codec;
    public uint i_original_fourcc;
    public int i_id;
    public libvlc_track_type_t i_type;
    public int i_profile;
    public int i_level;
    public IntPtr media;
    public uint i_bitrate;
    public IntPtr psz_language;
    public IntPtr psz_description;
}

顺便说一句,如果需要,很容易避免使用unsafe。虽然,如果你没有缺点,那么能够使用指针将使代码更容易编写。