Je rencontre un problème avec PInvocation de certaines fonctions WinAPI qui acceptent les structures WAVEFORMATEX
en tant que paramètres. Puisque la longueur de la structure WAVEFORMATEX
peut varier, j'ai implémenté une classe WaveFormatEX qui est rassemblée par une classe de marshaller personnalisée (qui implémente ICustmoMarshaller
). C'est à la suite d'un exemple fourni par Aaron Lerch dans son blog (Part 1, Part 2), mais avec quelques modifications de mon côté.C#: objet avec un marshaller personnalisé ne contenant pas de données après l'appel PInvoke
Quand j'appelle la fonction API de mon code, les méthodes et MarshalManagedToNative
MarshalNativeToManaged
du placier personnalisé sont appelés et à la fin de MarshalNativeToManaged
, l'objet géré contient les valeurs correctes. Mais lorsque l'exécution retourne à mon code appelant, l'objet WaveFormatEx
ne contient pas les valeurs lues lors de l'appel d'API.
Donc la question est: Pourquoi les données qui sont correctement ramenées de l'origine à la gestion n'apparaissent pas dans mon objet WaveFormatEx
après l'appel API natif? Qu'est-ce que je fais mal ici?
Edit:
Pour clarifier les choses, l'appel de fonction réussit, le fait de la marshalling l'objet WaveFormatEx
retour au code managé. Juste au moment où l'exécution revient de la méthode de marshalling à l'étendue à partir de laquelle la méthode a été appelée, l'objet WaveFormatEx
qui a été déclaré dans cette étendue d'appel ne contient pas les données de résultat.
Voici le prototype de fonction et la classe WAVEFORMATEX:
[DllImport("avifil32.dll")]
public static extern int AVIStreamReadFormat(
int Stream,
int Position,
[In, Out, MarshalAs(UnmanagedType.CustomMarshaler,
MarshalTypeRef = typeof(WaveFormatExMarshaler))]
WaveFormatEx Format,
ref int Size
);
[StructLayout(LayoutKind.Sequential)]
public class WaveFormatEx
{
public int FormatTag;
public short Channels;
public int SamplesPerSec;
public int AvgBytesPerSec;
public short BlockAlign;
public short BitsPerSample;
public short Size;
public byte[] AdditionalData;
public WaveFormatEx(short AdditionalDataSize)
{
WaveFormat.Size = AdditionalDataSize;
AdditionalData = new byte[AdditionalDataSize];
}
}
Les méthodes de triage ressemblent à ceci:
public object MarshalNativeToManaged(System.IntPtr NativeData)
{
WaveFormatEx ManagedObject = new WaveFormatEx(0);
ManagedObject = (WaveFormatEx)Marshal.PtrToStructure(
NativeData, typeof(WaveFormatEx));
ManagedObject.AdditionalData = new byte[ManagedObject.Size];
// If there is extra data, marshal it
if (ManagedObject.WaveFormat.Size > 0)
{
NativeData = new IntPtr(
NativeData.ToInt32() +
Marshal.SizeOf(typeof(WaveFormatEx)));
ManagedObject.AdditionalData = new byte[ManagedObject.WaveFormat.Size];
Marshal.Copy(NativeData, ManagedObject.AdditionalData, 0,
ManagedObject.WaveFormat.Size);
}
return ManagedObject;
}
public System.IntPtr MarshalManagedToNative(object Object)
{
WaveFormatEx ManagedObject = (WaveFormatEx)Object;
IntPtr NativeStructure = Marshal.AllocHGlobal(
GetNativeDataSize(ManagedObject) + ManagedObject.WaveFormat.Size);
Marshal.StructureToPtr(ManagedObject, NativeStructure, false);
// Marshal extra data
if (ManagedObject.WaveFormat.Size > 0)
{
IntPtr dataPtr = new IntPtr(NativeStructure.ToInt32()
+ Marshal.SizeOf(typeof(WaveFormatEx)));
Marshal.Copy(ManagedObject.AdditionalData, 0, dataPtr, Math.Min(
ManagedObject.WaveFormat.Size,
ManagedObject.AdditionalData.Length));
}
return NativeStructure;
}
Et voici mon code d'appel:
WaveFormatEx test = new WaveFormatEx(100);
int Size = System.Runtime.InteropServices.Marshal.SizeOf(test);
// After this call, test.FormatTag should be set to 1 (PCM audio),
// but it is still 0, as well as all the other members
int Result = Avi.AVIStreamReadFormat(AudioStream, 0, test, ref Size);
1) La cible est x86 2) La fonction réussit, et j'ai vérifié qu'elle renvoie des données en passant par 'MarshalNativeToManaged'. L'objet renvoyé par cette méthode a les données correctes. 3) Allouer le tampon manuellement et faire le marshalling en place est certainement une option, se penchera sur elle. 4) Cela explique - * Kaboom * est exactement ce qui s'y passe ... 5) Je connais NAudio, mais je voulais tout faire par moi-même (c'est un projet privé, autant dans le but d'apprendre des choses en créant un logiciel utile ...) En tout cas, merci beaucoup pour l'effort que vous avez mis dans votre réponse! – Treb