IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Marshalling struct décallage 2 bytes.


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Février 2005
    Messages
    41
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2005
    Messages : 41
    Par défaut Marshalling struct décallage 2 bytes.
    Bonjour,

    J'utilise actuellement un API (WvAPI.dll) natif (écrit en Ansi C) dans un développement dotNet frmaework 3.5.
    J'ai déjà construit une partie du marshalling.
    Cela semble bien fonctionner pour des structures simples mais j'ai quelques soucis pour cette structure:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    typedef enum WV_OPERATING_MODE
    {	
       WV_OPERATING_MODE_INVALID = 0,
       WV_OPERATING_MODE_MONITORING,
       WV_OPERATING_MODE_STANDBY,
       WV_OPERATING_MODE_READY,
       WV_OPERATING_MODE_BUSY,
       WV_OPERATING_MODE_PAPEROUT,
       WV_OPERATING_MODE_DOOR_OPEN,
       WV_OPERATING_MODE_COMM_FAILURE,
       WV_OPERATING_MODE_DEVICE_FAILURE,
       WV_OPERATING_MODE_NA,
       WV_OPERATING_MODE_DISCHARGE = WV_OPERATING_MODE_NA,
       WV_OPERATING_MODE_LAST = WV_OPERATING_MODE_NA
    } WV_OPERATING_MODE ;
     
    typedef int WV_CONNECT_ID ;
     
    typedef struct {
       TCHAR             PatientName  [WV_PATIENT_NAME_SIZE] ;
       TCHAR             PatientID    [WV_PATIENT_ID_SIZE] ;
       TCHAR             BedLabel     [WV_BED_LABEL_SIZE];
       TCHAR             CareUnit     [WV_CARE_UNIT_SIZE];
       TCHAR             FileName     [WV_FILE_NAME_SIZE];
       TCHAR             IPAddress    [WV_IP_ADDRESS_SIZE];
       TCHAR             MulticastIP  [WV_MULTICAST_IP_SIZE];
       TCHAR             DeviceType   [WV_DEVICE_TYPE_SIZE];
       WV_OPERATING_MODE DeviceStatus ;
       WV_CONNECT_ID     ConnectID ;  // 0 if not connected
       BOOL				 Wireless;
       TCHAR             HostName     [WV_HOSTNAME_SIZE] ;
    } WV_BED_DESCRIPTION ;
     
     
    typedef struct {
       WV_BED_DESCRIPTION WvBeds[WV_MAX_BEDS_PER_SERVER] ;
    } WV_BED_LIST ;
     
    IMPORT_FUNCTION int WINAPI WvListBeds(const TCHAR *pServerName, const TCHAR *pUserName, const TCHAR *pPassword, WV_BED_LIST *pBedList, int *pNumberOfBeds) ;
    Que j'ai mappé par l’intermédiaire du marshalling de la façon suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
     
            public enum WV_OPERATING_MODE
            {
                WV_OPERATING_MODE_INVALID = 0,
                WV_OPERATING_MODE_MONITORING,
                WV_OPERATING_MODE_STANDBY,
                WV_OPERATING_MODE_READY,
                WV_OPERATING_MODE_BUSY,
                WV_OPERATING_MODE_PAPEROUT,
                WV_OPERATING_MODE_DOOR_OPEN,
                WV_OPERATING_MODE_COMM_FAILURE,
                WV_OPERATING_MODE_DEVICE_FAILURE,
                WV_OPERATING_MODE_NA,
                WV_OPERATING_MODE_DISCHARGE = WV_OPERATING_MODE_NA,
                WV_OPERATING_MODE_LAST = WV_OPERATING_MODE_NA
            };
     
            [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
            public struct WV_BED_DESCRIPTION
            {
                [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = WV_PATIENT_NAME_SIZE)]
                public string PatientName;
                [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = WV_PATIENT_ID_SIZE)]
                public string PatientID;
                [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = WV_BED_LABEL_SIZE)]
                public string BedLabel;
                [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = WV_CARE_UNIT_SIZE)]
                public string CareUnit;
                [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = WV_FILE_NAME_SIZE)]
                public string FileName;
                [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = WV_IP_ADDRESS_SIZE)]
                public string IPAddress;
                [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = WV_MULTICAST_IP_SIZE)]
                public string MulticastIP;
                [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = WV_DEVICE_TYPE_SIZE)]
                public string DeviceType;
                public WV_OPERATING_MODE DeviceStatus;
                public int ConnectID;  // 0 if not connected
                public int Wireless;
                [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = WV_HOSTNAME_SIZE)]
                public string HostName;
            };
     
            [StructLayoutAttribute(LayoutKind.Sequential)]
            public struct WV_BED_LIST
            {
                [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = WV_MAX_BEDS_PER_SERVER, ArraySubType = UnmanagedType.Struct)]
                public WV_BED_DESCRIPTION[] WvBeds;
            };
     
            [DllImportAttribute(Constants.NATIVE_DLL, EntryPoint = "WvListBeds", CharSet = CharSet.Ansi)]
            public static extern int WvListBeds(
                [MarshalAsAttribute(UnmanagedType.LPStr)] string pServerName,
                [MarshalAsAttribute(UnmanagedType.LPStr)] string pUserName,
                [MarshalAsAttribute(UnmanagedType.LPStr)] string pPassword,
                ref WV_BED_LIST pBedList,
                ref int pNumberOfBeds);
    Ce que je constate c'est qu'à partir du champ DeviceStatus (qui est une énumération) la valeur retournée ne correspond pas à celle de l'application d'exemple fournie avec l'API. Tous les champs suivant sont affectés par cette erreur et on observe un décalage de 2 bytes.
    En effet, le champ Wireless vaut 0x50430000 or il doit être à 0x00000000.
    le valeurs 0x50 et 0x43 correspondent à de l'ASCII du string suivant HostName.
    Ainsi le HostName vaut "S207" alors qu'il doit valoir "CPS207".
    Les caractères C et P correspondent respectivement à 0x43 et 0x50 en ASCII.

    Pourriez-vous m'éclairer dans ce problème?
    Est-ce au niveau de l'énumération?

    Un tout grand merci pour la grande richesse de votre site web.

    KINDT Raphaël.

  2. #2
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Par défaut
    En ANSI C, quelle est la taille d'une enum ?
    En C#, c'est codé sur un Int32 mais tu peux demander à l'avoir sur un Int16 ou même un byte.

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Février 2005
    Messages
    41
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2005
    Messages : 41
    Par défaut
    J'ai déjà vérifié que la size était la même des deux côtés en faisant simplement ceci du côté C:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int sz = sizeof(WV_OPERATING_MODE)
    puis du côté C#:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int sz = sizeof(Wv.WV_OPERATING_MODE);
    Des deux côtés j'ai 4 bytes.
    J'ai même forcé l'usage d'un int à la place de l'enum dans le marshalling.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public int DeviceStatus;
    à la place de:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public WV_OPERATING_MODE DeviceStatus;
    J'ai même tenté un short pour voir mais le problème est toujours le même.
    J'ai créé une nouvelle solution avec deux projets: l'un qui génère une DLL native avec la même fonction et les mêmes structures et enum. L'autre qui effectue le marshaling et qui test le remplissage de la structure.
    Dans cette solution, tout semble fonctionner correctement, je n'ai pas de décalage de 2 bytes.

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Février 2005
    Messages
    41
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2005
    Messages : 41
    Par défaut
    J'imagine qu'une structure dot NET n'est pas du tout contenu dans une mémoire linéaire?
    Ainsi, après son mapping, je ne peux pas me fier au décalage de bytes qui affecterait d'autres champ de ma structure.

    En C#, c'est codé sur un Int32 mais tu peux demander à l'avoir sur un Int16 ou même un byte.
    Puis-je savoir comment faire?

  5. #5
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public enum WV_OPERATING_MODE : Int32 // ou Int16, ou byte
            {
    //blabla
    }
    Cela dit tu peux essayer ca:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    [StructLayout(LayoutKind.Explicit)]
    public struct Rect 
    {
       [FieldOffset(0)] public int left;
       [FieldOffset(4)] public int top;
       [FieldOffset(8)] public int right;
       [FieldOffset(12)] public int bottom;
    }
    http://msdn.microsoft.com/en-us/libr...kind.aspx#Y513

  6. #6
    Membre chevronné
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2011
    Messages
    269
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2011
    Messages : 269
    Par défaut
    Bonjour,

    Attention le marshalling C# est un peu spécial au niveau des alignements.
    Un Int32 se positionne (en octets) a un multiple de 4.
    La position de "DeviceID" est donc dépendante de la position de "DeviceType", si "DeviceType" est à l'octet 13 par exemple, et qu'il est codé sur 5 octets, et bien "DeviceID" n'est pas à l'octet 18 (13+5=18) mais à l'octet 20, 20 étant le prochain multiple de 4.
    De la même façon un Int16 se positionne sur un multiple de 2.

    Vérifies la longueur de tes chaines de caractère pour voir si elle n'induisent pas un décalage.

Discussions similaires

  1. Byte[] to struct
    Par kickoune dans le forum C#
    Réponses: 2
    Dernier message: 18/06/2014, 08h19
  2. Marshalling C struct en C#
    Par ncheboi dans le forum C#
    Réponses: 1
    Dernier message: 05/09/2011, 20h28
  3. modifier une struct marshallée en C#
    Par small_frenchy dans le forum C#
    Réponses: 1
    Dernier message: 19/09/2010, 14h55
  4. [Dvp.NET|A intégrer] [C#]Conversion struct <-> byte[]
    Par smyley dans le forum Contribuez
    Réponses: 2
    Dernier message: 14/12/2008, 14h04
  5. erreur IDL:omg.org/CORBA/MARSHAL:1.0
    Par Pinggui dans le forum CORBA
    Réponses: 3
    Dernier message: 13/05/2002, 15h05

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo