Domanda

Sto cercando di ottenere un'applicazione WPF C # per comunicare con un'altra applicazione scritta in C usando WM_COPYDATA. L'app C sta provando a inviare una struttura come segue:

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

Nella mia app C # ho definito una struttura come segue:

[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;
};

E il codice per ricevere il messaggio WM_COPYDATA è il seguente:

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;
}

Ricevo messaggi dall'applicazione C, ma tutti i dati nella struttura sono incomprensibili. In precedenza sono stato in grado di estrarre manualmente un array di byte dal puntatore lParam e quindi utilizzare System.BitConverter e System.Text.Encoding.ACII per interpretare l'array di byte e funzionava abbastanza bene. Ma ora sto cercando di farlo in modo più pulito e non funziona.

È stato utile?

Soluzione

Dopo molto tempo alla ricerca della risposta a questa domanda, mi sono reso conto che mi mancava un passaggio MOLTO importante. Mi sento un idiota, ma ecco la risposta alla mia domanda.

La struttura in C # dovrebbe apparire così:

[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;
};

E per definire le informazioni WM_COPYDATA è necessario definire un'altra struttura. Sembra così:

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

E il metodo WndProc dovrebbe essere modificato in questo modo:

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;
}

Stavo usando CopyDataStruct nella mia precedente soluzione funzionante e ho appena dimenticato di usarlo nella versione più recente.

Altri suggerimenti

Parte del problema è che il membro str deve essere un ByValTStr non un LPSTR poiché è un array di stringhe inline. Prova la seguente definizione

[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;
};
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top