Как отобразить объединение C с const char * в C # struct? - PullRequest
6 голосов
/ 05 июля 2011

В функции обратного вызова из нативной библиотеки мне нужно получить доступ к массиву espeak_EVENT.Проблема в выражении UNION в исходном коде C:

typedef struct {
    espeak_EVENT_TYPE type;
    unsigned int unique_identifier; // message identifier (or 0 for key or character)
    int text_position;    // the number of characters from the start of the text
    int length;           // word length, in characters (for espeakEVENT_WORD)
    int audio_position;   // the time in mS within the generated speech output data
    int sample;           // sample id (internal use)
    void* user_data;      // pointer supplied by the calling program
    union {
        int number;        // used for WORD and SENTENCE events. For PHONEME events this is the phoneme mnemonic.
        const char *name;  // used for MARK and PLAY events.  UTF8 string
    } id;
} espeak_EVENT;

У меня есть

[StructLayout(LayoutKind.Explicit)]
        public struct espeak_EVENT
        {
            [System.Runtime.InteropServices.FieldOffset(0)]
            public espeak_EVENT_TYPE type;

            [System.Runtime.InteropServices.FieldOffset(4)]
            public uint unique_identifier;  // message identifier (or 0 for key or character)

            [System.Runtime.InteropServices.FieldOffset(8)]
            public int text_position;    // the number of characters from the start of the text

            [System.Runtime.InteropServices.FieldOffset(12)]
            public int length;           // word length, in characters (for espeakEVENT_WORD)

            [System.Runtime.InteropServices.FieldOffset(16)]
            public int audio_position;   // the time in mS within the generated speech output data

            [System.Runtime.InteropServices.FieldOffset(20)]
            public int sample;           // sample id (internal use)

            [System.Runtime.InteropServices.FieldOffset(24)]
            public IntPtr user_data;      // pointer supplied by the calling program

            [System.Runtime.InteropServices.FieldOffset(32)]
            public int number;

            [System.Runtime.InteropServices.FieldOffset(32)]
            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)]
            public string name; 
        }

А затем

public static Int32 SynthCallback(IntPtr wav, Int32 numsamples, IntPtr eventsParameter)
        {
            if (wav == IntPtr.Zero) 
                return 0;

            int j=0;
            while(true)
            {
                System.IntPtr ptr = new IntPtr( 
                                                (
                                                    eventsParameter.ToInt64() 
                                                    + (j *
                                                        System.Runtime.InteropServices.Marshal.SizeOf(typeof(cEspeak.espeak_EVENT))
                                                      ) 
                                                )
                                              );
                if(ptr == IntPtr.Zero)
                    Console.WriteLine("NULL");

                cEspeak.espeak_EVENT events = (cEspeak.espeak_EVENT) System.Runtime.InteropServices.Marshal.PtrToStructure(ptr, typeof(cEspeak.espeak_EVENT));

                if(events.type == cEspeak.espeak_EVENT_TYPE.espeakEVENT_SAMPLERATE)
                {
                    Console.WriteLine("Heureka");
                }
                break;


                //Console.WriteLine("\t\t header {0}: address={1}: offset={2}\n", j, info.dlpi_phdr, hdr.p_offset);
                ++j;
            }


            if(numsamples > 0)
            {
                byte[] wavbytes = new Byte[numsamples * 2];
                System.Runtime.InteropServices.Marshal.Copy(wav, wavbytes, 0, numsamples*2);
                bw.Write(wavbytes, 0, numsamples*2);
            }
            return 0;
        }

Но оно всегда терпит неудачу на

cEspeak.espeak_EVENT events = (cEspeak.espeak_EVENT) System.Runtime.InteropServices.Marshal.PtrToStructure(ptr, typeof(cEspeak.espeak_EVENT));

Однако, когда я удаляю

[System.Runtime.InteropServices.FieldOffset(32)][System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)]
            public string name; 

из espeak_event, тогда это работает.

Как я могу сделать эту работу, не удаляя строку в объединении?Мне нужно получить к нему доступ в функции обратного вызова.

Редактировать: И, кстати, что произойдет со смещением полей, если я позволю ему работать на x64, и размером "public IntPtr user_data;"меняется с 32 на 64 бита?

Хм, если подумать, правильно ли смещено fieldoff 32?Кажется, я перепутал размер указателя, когда думал о x64.Это вполне может быть еще одна ошибка.

Хм, объединение с int и char *, я думаю, они никогда не скомпилировали его для x64.Потому что sizof (int) является 32-битной в системе x64 Linux.

Ответы [ 3 ]

3 голосов
/ 05 июля 2011

Объявите name как IntPtr вместо string, а затем используйте Marshal.PtrToStringAnsi, чтобы получить его в строковую переменную.

Я игнорирую тот факт, что содержимое строки - UTF-8,Если ваш текст чистый ASCII, это нормально.Если нет, то вам нужно скопировать в массив byte[] и затем преобразовать из UTF-8 с помощью Encoding.UTF8.GetString.

0 голосов
/ 05 июля 2011

Можете ли вы сначала маршалировать структуру только с espeak_EVENT_TYPE type?Затем вы можете выбрать одну из двух структур в зависимости от того, что вы ожидаете найти в содержимом объединения: одна имеет только int number, а другая - только const char *name.

0 голосов
/ 05 июля 2011

Теперь это может показаться чрезмерно трудоемким, но всякий раз, когда я сталкиваюсь с ситуацией, когда мне необходимо получить доступ через привязку к некоторой структуре C, использующей специфические функции C (например, союзы или указатели void*), я обычно пишу набор get /устанавливать функции из / в нативные (маршаллинг) типы целевого языка в C и предоставлять их через привязку, а саму структуру сохранять непрозрачной.

...