2010-07-27 3 views
11

Je veux P/Invoke à GetWindowLongPtr et SetWindowLongPtr, et je vois des informations contradictoires à leur sujet. Certaines sources indiquent que, sur les plateformes 32 bits, GetWindowLongPtr est juste une macro de préprocesseur qui appelle GetWindowLong et GetWindowLongPtr n'existe pas en tant que point d'entrée dans user32.dll. Par exemple:Comment faire un pin-back sur GetWindowLongPtr et SetWindowLongPtr sur des plates-formes 32 bits?

  • Le pinvoke.net entry for SetWindowLongPtr a une méthode statique qui vérifie IntPtr.Size et appelle ensuite soit SetWindowLong ou SetWindowLongPtr, avec un commentaire disant que « les systèmes d'exploitation existants ne prennent pas en charge SetWindowLongPtr ». Il n'y a pas d'explication de ce que l'on entend par "systèmes d'exploitation hérités".
  • Un état answer on StackOverflow "Sur les systèmes 32 bits GetWindowLongPtr est juste une macro C qui pointe vers GetWindowLong".

Ainsi, ces sources semblent indiquer que les points d'entrée * Ptr ne sont tout simplement pas là dans la version de user32.dll livré avec, par exemple, 32 bits de Windows 7.

Mais je ne vois pas indication de cela dans la documentation MSDN. Selon MSDN, SetWindowLongPtr remplace SetWindowLong, simple et simple. Et selon la section des exigences du SetWindowLongPtr page, il semble que SetWindowLongPtr a été dans user32.dll depuis Windows 2000 (éditions client et serveur). Encore une fois, aucune mention des points d'entrée manquants dans les systèmes d'exploitation 32 bits.

Je suspect que la vérité est quelque part entre: que lorsque vous dites au compilateur C++ pour cibler plus anciens systèmes d'exploitation (c.-à-compiler quelque chose qui fonctionnera sur Win9x et NT4), les fichiers d'en-tête déclare SetWindowLongPtr comme macro qui appelle SetWindowLong, mais le point d'entrée existe probablement dans Windows 2000 et versions ultérieures et vous l'obtiendrez directement (au lieu de la macro) si vous dites au compilateur de cibler ces plates-formes. Mais c'est juste une supposition; Je n'ai pas vraiment les ressources ou le savoir-faire pour creuser et vérifier.

Il est également possible que la plate-forme cible joue un rôle: si vous compilez votre application pour la plate-forme x86, vous ne devez pas appeler SetWindowLongPtr sur un système d'exploitation 64 bits. Encore une fois, j'en connais assez pour penser à la question, mais je ne sais pas comment trouver la réponse. MSDN semble suggérer que SetWindowLongPtr est toujours correct.

Quelqu'un peut-il me dire s'il est sûr de simplement P/Invoke to SetWindowLongPtr et d'en avoir terminé avec lui? (Supposons que Windows 2000 et versions ultérieures.) Would P/Invoquer à SetWindowLongPtr me donner le point d'entrée correcte:

  • si je lance une application ciblant la plate-forme x86 sur un système d'exploitation 32 bits?
  • si j'exécute une application ciblant la plate-forme x86 sur un système d'exploitation 64 bits?
  • si j'exécute une application ciblant la plate-forme x64 sur un système d'exploitation 64 bits?

Répondre

15

Je vous recommande de traiter ce la façon dont Windows Forms fait en interne:

public static IntPtr GetWindowLong(HandleRef hWnd, int nIndex) 
{ 
    if (IntPtr.Size == 4) 
    { 
     return GetWindowLong32(hWnd, nIndex); 
    } 
    return GetWindowLongPtr64(hWnd, nIndex); 
} 


[DllImport("user32.dll", EntryPoint="GetWindowLong", CharSet=CharSet.Auto)] 
private static extern IntPtr GetWindowLong32(HandleRef hWnd, int nIndex); 

[DllImport("user32.dll", EntryPoint="GetWindowLongPtr", CharSet=CharSet.Auto)] 
private static extern IntPtr GetWindowLongPtr64(HandleRef hWnd, int nIndex); 
+3

Vous n'avez pas indiqué où vous avez trouvé ce code, mais je l'ai suivi sur System.Windows.Forms.UnsafeNativeMethods. –

+0

@ hans-passant: Merci pour ce peu de code. Il a été utile de mettre en œuvre une solution pour avoir un dialogue modal vers une autre boîte de dialogue: http://stackoverflow.com/a/16088711/654244 – KyleK

+1

L'attribut ne devrait-il pas inclure SetLastError = true pour récupérer correctement une éventuelle erreur plus tard? –

3
  1. Ouvrez le fichier d'en-tête (sur la page MSDN, ceci est répertorié comme Winuser.h). Les en-têtes Win32 se trouvent généralement à C:\Program Files\Microsoft SDKs\Windows\v7.0A\Include
  2. Rechercher toutes les instances de SetWindowLongPtr/GetWindowLongPtr.
  3. Notez que lorsque _WIN64 est défini, ils sont des fonctions; quand ce n'est pas, ils sont #define 'd à SetWindowLong/GetWindowLong.

Cela implique que les systèmes d'exploitation 32 bits ne peuvent pas avoir SetWindowLongPtr/GetWindowLongPtr comme une fonction réelle, il semble que le commentaire sur pinvoke.net est correcte.

mise à jour (plus de précisions sur _WIN64):

_WIN64 est défini par le C/C++ compilateur lors de la compilation du code 64 bits (qui ne fonctionne que sur un système d'exploitation 64 bits). Cela signifie donc que tout code 64 bits utilisant SetWindowLongPtr/GetWindowLongPtr utilisera les fonctions réelles, mais tout code 32 bits qui les utilise utilisera SetWindowLong/GetWindowLong à la place. Cela inclut le code 32 bits exécuté sur un système d'exploitation 64 bits.

Pour émuler le même comportement en C#, je recommande de vérifier IntPtr.Size comme fait par pinvoke.net; cela vous indique si vous exécutez du code 32 bits ou 64 bits. (Garder à l'esprit que le code 32 bits peut s'exécuter sur un système d'exploitation 64 bits). L'utilisation de IntPtr.Size dans le code managé émule le même comportement que _WIN64 pour le code natif.

+0

Mon répertoire 'v7.0A' ne dispose pas d'un sous-répertoire' Include' - juste '' Bin' et Bootstrapper'. J'ai trouvé un 'Include' sous' v5.0', cependant. –

+0

Même offre. Ils sont juste différentes versions du SDK Win32. –

Questions connexes