How to define structure with dynamic length array inside in ctypes?

585 Views Asked by At

I want to use a dll function which returns AP ssid list in Python, But it takes a preallocated struct with dyamic length array inside. I don't know how to define such a structure, without knowing the returned array length in advance.

Below is how the definition looks like in the C# demo; specifically the SSID byte array length in this struct varies.

    public extern static bool D300SysUI_WiFiGetAroundSsidStatus(IntPtr SSIDList, int nMaxCount);

    public struct SSIDLISTNET
    {
        public uint ATIMWindow;
        public D300SysUI.NDIS_802_11_AUTHENTICATION_MODE AuthenticationMode;
        public uint BeaconPeriod;
        public uint DSConfig;
        public uint DwellTime;
        public uint HopPattern;
        public uint HopSet;
        public D300SysUI.NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
        public byte[] MacAddress;
        public D300SysUI.NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
        public uint NumberOfItems;
        public uint Privacy;
        public byte[] Reserved;
        public int Rssi;
        public byte[] Ssid;
        public uint SsidLength;
        public byte[] SupportedRates;
    }

Do I need to create_string_buffer long enough by estimation ? And loop through the returned buffer, byte by byte and assmebly the bytes into element by size?

If that is the right way, how do I determine the end of the dymamic arrays ? (please pardon my ignorance, I am new to ctypes/c++)

PS: Example from the C# SDK

        //D300SysUI.SSIDLIST[] items= new D300SysUI.SSIDLIST[30];
        //IntPtr[] ptArray = new IntPtr[1];
        //ptArray[0] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(D300SysUI.SSIDLIST)) * 30);
        //bool b = D300SysUI.D300SysUI_WiFiGetAroundSsidStatus(ptArray[0], 30);
        //string message = "";
        //string mac = "";
        //if (b)
        //{
        //    items[0] = (D300SysUI.SSIDLIST)Marshal.PtrToStructure((IntPtr)((UInt32)ptArray[0]), typeof(D300SysUI.SSIDLIST));
        //    for (int i =0;i<6;i++)
        //    {
        //        mac += String.Format("{0:X2} ", items[0].MacAddress[i]);
        //    }

        //    message += string.Format("AP:{0},MAC:{1},dBm:{2} \r\n",Encoding.GetEncoding("ASCII").GetString(items[0].Ssid,0,(int)(items[0].SsidLength)),mac,items[0].Rssi);

        //    for (int j = 1; j < items[0].NumberOfItems; j++)
        //    {
        //        items[j] = (D300SysUI.SSIDLIST)Marshal.PtrToStructure((IntPtr)((UInt32)ptArray[0] + j * Marshal.SizeOf(typeof(D300SysUI.SSIDLIST))), typeof(D300SysUI.SSIDLIST));
        //        mac = "";
        //        for (int i = 0; i < 6; i++)
        //        {
        //            mac += String.Format("{0:X2} ", items[j].MacAddress[i]);
        //        }

        //        message += string.Format("AP:{0},MAC:{1},dBm:{2} \r\n", Encoding.GetEncoding("ASCII").GetString(items[j].Ssid, 0, (int)(items[j].SsidLength)), mac, items[j].Rssi);

        //    }
        //}
        //Marshal.FreeHGlobal(ptArray[0]);
        //MessageBox.Show(message);
1

There are 1 best solutions below

2
tripleee On

If you have defined SSIDLISTNET as a cTypes structure, you just allocate the desired number of these. If the maximum the API will return is 30, allocating that number of instances is a simple and straightforward solution.

SSIDlist = SSIDLISTNET * 30

If you are very constrained on memory, you can probably copy over the required actual number of items to a new list which only holds that many, and del SSIDlist to free up the memory you reserved for this list (or let it go out of scope).