Avatar billede matiasdk Nybegynder
08. april 2006 - 18:42 Der er 13 kommentarer og
1 løsning

Pointers (ArrayList to IntPtr and back)

Hejsa

Jeg sidder og roder med pointers i forbindelse med bl.a. EnumChildWindows, og jeg vil gerne sende en ArrayList videre som lParam.

Er der nogen der kort kan forklare hvordan man konverterer til og fra IntPtr, og hvordan man bruger dem fornuftigt i forhold til Win32 API? Der er også noget med at man ikke bruge bool og int som return types, eller bare i det hele taget, mht. 64 bit systemer. Hvad går det ud på?

Tak
Avatar billede arne_v Ekspert
09. april 2006 - 04:30 #1
du kan vel ikke sende en System.Collection.ArrayList til en Win32 API funktion ??

Marshal.ReadIntPtr
Marshal.PtrToStringAnsi
Marshal.Copy
Marshal.StructureToPtr

er nogle af de metoder jeg har brugt på IntPtr
Avatar billede matiasdk Nybegynder
09. april 2006 - 13:15 #2
Hej Arne,

Jo, for i forbindelse med EnumChildWindows vil jeg gerne have at den indsætter undervinduer i arraylisten som IntPtr objekter..

Jeg kan forstå at hele idéen med lParam er, at man netop kan sende arrays eller strings som pointers.

Altså vil jeg gerne vide hvordan jeg tager pointeren til Arraylisten og tildeler den som en IntPtr. Og omvendt.
Avatar billede driis Nybegynder
09. april 2006 - 14:04 #3
Det kan du opnå ved at lade din ArrayList være et felt på klassen og blot tilføje til denne når callback funktionen kører.

Er det alligevel nødvendigt, skal du bruge et GCHandle (Garbage-Collector Handle), som dels gør at objektet ikke bliver garbage collected og dels at det ikke bliver flyttet fra dens memory plads. Endelig er der en metode, som muliggør at du kan få fat på GCHandle objektet ud fra en IntPtr til det, uden selv at skulle caste. Husk altid at Free() et GCHandle når du er færdig med det.

Jeg poster lige et eksempel:
Avatar billede driis Nybegynder
09. april 2006 - 14:05 #4
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace EnumChildrenTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Children to desktop window:");
            List<IntPtr> list = WindowEnumerator.GetChildren(WindowEnumerator.GetDesktopWindow());
            foreach (IntPtr ptr in list)
            {
                Console.WriteLine(ptr);
            }
        }
    }
   
    public class WindowEnumerator
    {
        /// <summary>
        /// Gets the children.
        /// </summary>
        /// <param name="hwndParent">The HWND parent.</param>
        /// <returns></returns>
        public static List<IntPtr> GetChildren(IntPtr hwndParent)
        {
            List<IntPtr> list = new List<IntPtr>();
            GCHandle handle = GCHandle.Alloc(list);
            try
            {
                EnumChildWindows(hwndParent, new EnumWindowProc(EnumWindowCallback), GCHandle.ToIntPtr(handle));
            }
            finally
            {
                if (handle.IsAllocated)
                    handle.Free();
            }
            return list;
        }

        private static bool EnumWindowCallback(IntPtr hwndChild, IntPtr lParam)
        {
            GCHandle handle = GCHandle.FromIntPtr(lParam);
            List<IntPtr> list = handle.Target as List<IntPtr>;
            if (list != null)
                list.Add(hwndChild);
            else
                throw new InvalidCastException("lParam did not point to a List of IntPtr");
            return true;
        }

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowProc callback, IntPtr lParam);

        [DllImport("user32.dll")]
        public static extern IntPtr GetDesktopWindow();
       
        [return: MarshalAs(UnmanagedType.Bool)]
        delegate bool EnumWindowProc(IntPtr hwndChild, IntPtr lParam);
       
    }
}
Avatar billede matiasdk Nybegynder
09. april 2006 - 15:31 #5
Hvad søren betyder    "List<IntPtr> list = new List<IntPtr>();"

Jeg har i øvrigt set eksemplet du benytter før. Jeg skal bruge NET 1.1, så System.Collections.Generic duer vist ikke :-)
Avatar billede arne_v Ekspert
09. april 2006 - 15:45 #6
så bruger du jo bare en ArrayList og caster når du henter ud
Avatar billede arne_v Ekspert
09. april 2006 - 15:47 #7
og når det er et callback til .NET kode, så giver en ArrayList jo pludselig mening
Avatar billede matiasdk Nybegynder
09. april 2006 - 15:56 #8
Arne: Ja ikke? :-)

Mener du, at jeg så bare skal skrive:
"ArrayList list = new ArrayList();"    i stedet for "List<IntPtr> list = new List<IntPtr>();"  ?

Jeg har ikke mulighed for at prøve det lige nu, men jeg ville for så vidt også gerne have det andet forklaret hvis muligt.
Avatar billede driis Nybegynder
09. april 2006 - 16:02 #9
Ja, du kan blot bruge en ArrayList istedet for den generiske List. Og så selvfølgelig ændre castet i callback funktionen.
Avatar billede matiasdk Nybegynder
10. april 2006 - 10:49 #10
Som nævnt, skal jeg altså bruge .NET 1.1 frameworket. Som det ses i følgende, er GCHandle.FromIntPtr() en .NET 2.0 funktion. Andre løsningsforslag?

http://msdn2.microsoft.com/en-US/library/system.runtime.interopservices.gchandle.fromintptr(VS.80).aspx
Avatar billede matiasdk Nybegynder
10. april 2006 - 12:07 #11
Nå. Man kan åbenbart bare gøre det explicit, altså:

EnumChildWindows(hwndParent, new EnumWindowProc(EnumWindowCallback), (IntPtr)handle);

og

GCHandle handle = (GCHandle)lParam;


Det ser ud til at virke fint. Kan I dog forklare hvad "List<IntPtr> list = new List<IntPtr>();" går ud på? Altså jeg har ikke set <> brugt i C# før...
Avatar billede driis Nybegynder
10. april 2006 - 18:24 #12
Jeg havde ikke lige lagt mærke til at FromIntPtr var 2.0 specifikt; men fint at du fandt en løsning alligevel.

"List" er en af de nye klasser i .NET Framework 2.0. < > er notationen for generics, som er en ny feature i C# 2.0. Populært sagt kan du med generics skrive samme kode der kan arbejde på flere forskellige typer. I eksemplet betyder List<IntPtr>: " en liste der arbejder på IntPtr", og Add metoden tager derfor IntPtr som argument, og indexeren returnerer IntPtr (i stedet for object, som på en arraylist). Dvs. du sparer nogle casts, og listen er typesikker, dvs. du kan være 100% sikker på at listen kun indeholder IntPtr's.

Collections som f.eks. List, er en af de helt oplagte steder at bruge Generics, men det kan også bruges til mange andre formål.
Avatar billede arne_v Ekspert
10. april 2006 - 19:08 #14
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester