Question

J'essaie de faire communiquer une application WPF C # avec une autre application écrite en C à l'aide de WM_COPYDATA. L’application C tente d’envoyer une structure comme suit:

typedef struct
{
    int x;
    int y;
    char str[40];
    double d;
    char c;
} DATASTRUCT;

Dans mon application C #, j'ai défini une structure comme suit:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct DATASTRUCT
{
    public int x;
    public int y;
    [MarshalAs(UnmanagedType.LPStr, SizeConst=40)]
    public string s;
    public double d;
    public char c;
};

Et le code pour recevoir le message WM_COPYDATA est le suivant:

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    hwndSource = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
    hwndSource.AddHook(new HwndSourceHook(WndProc));
}

private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    if (msg == 0x4A)
    {
        DATASTRUCT data = (DATASTRUCT)Marshal.PtrToStructure(lParam, typeof(DATASTRUCT));
        this.updateText(data);
        handled = true;
    }

    return (IntPtr)0;
}

Je reçois des messages de l'application C, mais toutes les données de la structure sont du charabia. Avant cela, je pouvais extraire manuellement un tableau d'octets à partir du pointeur lParam puis utiliser System.BitConverter et System.Text.Encoding.ACII pour interpréter le tableau d'octets, et cela fonctionnait plutôt bien. Mais maintenant, j'essaie de le faire de manière plus propre et cela ne fonctionne tout simplement pas.

Était-ce utile?

La solution

Après avoir longuement cherché la réponse à cette question, j'ai compris qu'il me manquait une étape TRÈS importante. Je me sens idiot, mais voici la réponse à ma propre question.

La structure C # devrait ressembler à ceci:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public unsafe struct DataStruct
{
    public int x;
    public int y;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=40)]
    public string s;
    public double d;
    public char c;
};

Et une autre structure doit être définie pour recevoir les informations WM_COPYDATA. Cela ressemble à ceci:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public unsafe struct CopyDataStruct
{
    public IntPtr dwData;
    public int cbData;
    public IntPtr lpData;
}

Et la méthode WndProc doit être modifiée pour ressembler à ceci:

private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    if (msg == 0x4A)
    {
        CopyDataStruct cps = (CopyDataStruct)Marshal.PtrToStructure(lParam, typeof(CopyDataStruct));
        DataStruct data = (DataStruct)Marshal.PtrToStructure(cps.lpData, typeof(DataStruct));
        updateText(data);
        handled = true;
    }

    return (IntPtr)0;
}

J'utilisais CopyDataStruct dans ma solution de travail précédente et j'ai tout simplement oublié de l'utiliser dans la nouvelle version.

Autres conseils

Une partie du problème est que le membre str doit être un ByValTStr et non un LPSTR puisqu'il s'agit d'un tableau de chaînes en ligne. Essayez la définition suivante

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct DATASTRUCT
{
    public int x;
    public int y;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=40)]
    public string s;
    public double d;
    public char c;
};
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top