2010-12-09 42 views
2

J'ai mis un post hier, Comment créer des structures pour C# écrites à l'origine en C++.Comment initialiser un pointeur non sécurisé en C# et le convertir en octet []?

Merci pour vos réponses. J'essaie, sans grand succès, d'utiliser DeviceIOControl sur une plate-forme ARM fonctionnant sous WinCE 6.0 et .NET Compact framework 2.0 Tout ce que j'essaie de faire, c'est de contrôler une broche de port et cela s'avère être un cauchemar.

Voici la déclaration PInvoke:

[DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)] 
internal static extern bool DeviceIoControlCE(int hDevice, 
              int dwIoControlCode, 
              byte[] lpInBuffer, 
              int nInBufferSize, 
              byte[] lpOutBuffer, 
              int nOutBufferSize, 
              ref int lpBytesReturned, 
              IntPtr lpOverlapped); 

La déclaration PInvoke suggère un octet [] peut être transmis à simplement. Il est certainement facile d'écrire les valeurs de chaque membre d'une structure, de le convertir en un tableau d'octets et de le passer à la DLL.

Je donne les résultats suivants:

[StructLayout(LayoutKind.Sequential)] 
    public struct pio_desc 
    { 
     unsafe byte* pin_name;  //Length??? 
     public uint pin_number;  //4 bytes 
     public uint default_value; //4 bytes 
     public byte attribute;  //1 byte 
     public uint pio_type;  //4 bytes 
    } 

et

pio_desc PA13 = new pio_desc();

Alors sûrement maintenant il est une question de faire quelque chose comme:

PA13.pin_number = AT91_PIN_PA13;  //Length 4 bytes 
PA13.default_value = 0;    //Length 4 bytes 
PA13.attribtue = PIO_DEFAULT;   //Length 1 byte 
PA13.pio_type = PIO_OUTPUT;   //Length 4 bytes 

et à convertir (pin_number par exemple) à un octet []:

byte[] temp = BitConverter.GetBytes(PA13.pin_number); //uints are 4 bytes wide 
     byteArray[++NumberOfChars] = temp[0]; 
     byteArray[++NumberOfChars] = temp[1]; 
     byteArray[++NumberOfChars] = temp[2]; 
     byteArray[++NumberOfChars] = temp[3];  //Will need to check on Endianess 

Questions:

En la structure PA13, comment initialiser le pointeur pin_name? L'auteur du pilote note que ce n'est pas utilisé, vraisemblablement par son chauffeur. Est-ce que Windows aura besoin de cela pour avoir de la valeur?

PA13.pin_name = ??????

Ensuite, comment puis-je convertir ce pointeur en un octet pour entrer dans mon tableau byte [] à passer à DeviceIOControl?

Je suis devenu assez déçu et frustré de voir à quel point il est difficile de changer le niveau de tension d'une broche de port - j'ai lutté avec ce problème pendant des jours maintenant. Parce que je viens d'un environnement matériel, je pense qu'il sera plus facile (et moins éligant) pour moi d'implémenter le contrôle d'E/S sur un autre contrôleur et de lui transmettre des données de contrôle via un port COM.

Merci encore pour toute assistance (simple).

+0

Pouvez-vous coller la définition de structure non gérée? Il semble que 'pin_name' est en fait supposé être une chaîne de style C, car un port littéral de la structure proviendrait de' char * pin_name'. Si tel est le cas, vous pouvez utiliser '[MarshalAs (UnmanagedType.LPStr)] chaîne publique nom_broche;' dans la structure. – cdhowie

+0

Merci pour l'intérêt! La structure non-gérée est: struct pio_desc { \t const char * nom_fichier;/* Nom de la broche */ \t unsigned int pin_num;/* Numéro de broche */ \t unsigned int dft_value;/* Valeur par défaut pour les sorties */ \t attribut char non signé; \t enum type_pio_type; }; Je souhaite remplacer l'enum par un type de données int ou byte. Selon une note technique que j'ai sur cette structure, l'auteur dit que le nom de Pin n'est pas utilisé. Il semble étrange de l'inclure alors, mais je pense que le référencement d'une épingle se fait par un nombre à la place. – Gary

Répondre

0

Déclarez lpInBuffer et lpOutBuffer comme IntPtr. Initialisez-les en utilisant Marshal.AllocHGlobal (n'oubliez pas de les libérer avec Marshal.FreeHGlobal à la fin). Remplissez ces tampons et lisez-les en utilisant différentes surcharges Marshal.Copy.

1

Vous aurez besoin de faire quelques petites choses ici. Tout d'abord, remplacer ce membre:

unsafe byte* pin_name;  //Length??? 

avec:

[MarshalAs(UnmanagedType.LPStr)] public string pin_name; 

Remplacez ensuite le/sortie des tampons dans la déclaration P/Invoke de byte[] à IntPtr.Ensuite, vous pouvez utiliser ce code pour convertir les données:

pio_desc PA13; 
// Set the members of PA13... 

IntPtr ptr = IntPtr.Zero; 
try { 
    var size = Marshal.SizeOf(PA13); 
    ptr = Marshal.AllocHGlobal(size); 

    Marshal.StructureToPtr(PA13, ptr, false); 

    // Your P/Invoke call goes here. 
    // size will be the "nInBufferSize" argument 
    // ptr will be the "lpInBuffer" argument 
} finally { 
    if (ptr != IntPtr.Zero) { 
     Marshal.DestroyStructure(ptr, typeof(pio_desc)); 
     Marshal.FreeHGlobal(ptr); 
    } 
} 
+0

Salut, merci pour l'aide! J'ai implémenté ce code, cependant, que passerais-je au paramètre int nInBufferSize? J'ai essayé quelques trucs et aucun n'a fonctionné: une erreur 'Exception non supportée' a été renvoyée. – Gary

+0

Vous passeriez 'Marshal.SizeOf (PA13)'. Laissez-moi mettre à jour le code. Aussi, pouvez-vous préciser quelle ligne vous obtenez cette exception? – cdhowie

+0

Je reçois l'exception sur ptr = Marshal.AllocHGlobal (Marshal.SizeOf (PA13)); Est-ce normal de se battre si longtemps avec cette fonction DeviceIOControl? Il semble y avoir beaucoup de gens qui posent des questions à ce sujet. Merci encore pour votre aide car je suis à la fin de ma vie. Une autre chose qui ne semblait pas fonctionner: il n'y a pas de méthode DestroyStructure disponible dans le menu sur mon PC. Je cours. NET compact qui peut être le problème avec toute cette chose. – Gary

1

Vous pouvez faire cela beaucoup plus facile en mentant sur la déclaration [DllImport]. Déclarez simplement l'argument lpInBuffer comme type de structure, le marshaller pinvoke le convertira en un pointeur quand même. Ainsi:

[DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)] 
internal static extern bool SetOutputPin(IntPtr hDevice, 
              int dwIoControlCode, 
              ref pio_desc lpInBuffer, 
              int nInBufferSize, 
              IntPtr lpOutBuffer, 
              int nOutBufferSize, 
              out int lpBytesReturned, 
              IntPtr lpOverlapped); 

Utilisation de IntPtr pour lpOutBuffer car le pilote ne renvoie probablement rien. Passez IntPtr.Zero. Même idée avec la structure. Si le champ n'est pas utilisé alors simplement déclarer comme IntPtr:

[StructLayout(LayoutKind.Sequential)] 
public struct pio_desc 
{ 
    public IntPtr pin_name;  // Leave at IntPtr.Zero 
    public uint pin_number;  //4 bytes 
    public uint default_value; //4 bytes 
    public byte attribute;  //1 byte 
    public uint pio_type;  //4 bytes 
} 

Soyez prudent sur la propriété d'emballage, il fait ici une différence en raison de l'octet champ taille. Vous pouvez avoir besoin de 1 mais c'est juste une supposition sans rien savoir sur le pilote. Si vous avez du code C, alors testez la valeur de sizeof (pio_desc) et comparez avec Marshal.SizeOf(). Passez Marshal.SizeOf (typeof (pio_desc)) en tant qu'argument nInBufferSize. Si vous aviez posté les déclarations C, cela aurait été plus facile de répondre avec précision.

+0

Argh, m'a creusé! :) –

+0

Il il !! Merci pour la réponse!! Je vais jeter un coup d'oeil à ceci aussi, pendant que je décide de ce qu'il faut faire ensuite si cette fonction ne marche pas! – Gary