2009-10-28 14 views
4

J'essaie d'obtenir une application C# WPF pour communiquer avec une autre application écrite en C à l'aide de WM_COPYDATA. L'application C tente d'envoyer un struct comme suit:Structures de regroupement à partir de messages WM_COPYDATA

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

Dans mon application C# J'ai défini une struct 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 la suivante: Je reçois des messages de l'application C, mais toutes les données dans la structure sont charabia. Avant cela, j'étais capable d'extraire manuellement un tableau d'octets à partir du pointeur lParam, puis d'utiliser System.BitConverter et System.Text.Encoding.ACII pour interpréter le tableau d'octets, et cela a plutôt bien fonctionné. Mais maintenant j'essaie de le faire d'une manière plus propre et ça ne marche pas.

Répondre

6

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

La struct 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 un autre struct doit être défini pour recevoir l'info WM_COPYDATA. Il 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é 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 la CopyDataStruct dans ma solution de travail précédente, et j'ai oublié de l'utiliser dans la nouvelle version.

2

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