简体   繁体   中英

How to call sysctl from Xamarin iOS?

I'm banging my head about how to properly call sysctlbyname from C# directly. I've read the man page and I think what I'm doing is very close, just something is messed up with marshalling.

     [DllImport(MonoTouch.Constants.SystemLibrary)]  
    internal static extern int sysctlbyname( [MarshalAs(UnmanagedType.LPStr)] string property, IntPtr output, IntPtr oldLen, IntPtr newp, uint newlen);

    //only works on sysctls that return strings
    public static string SystemStringInfo(string property)
    {
        GCHandle? lenh = null, valh = null;
        try
        {
            object len = 0L;
            lenh=GCHandle.Alloc(len, GCHandleType.Pinned);

            byte[] val;
            int status = sysctlbyname(property, IntPtr.Zero, GCHandle.ToIntPtr(lenh.Value), IntPtr.Zero, 0); //crash here
            if (status == 0)
            {

                val = new byte[(Int64)len];
                valh=GCHandle.Alloc(val, GCHandleType.Pinned);
                status = sysctlbyname(property, GCHandle.ToIntPtr(valh.Value), GCHandle.ToIntPtr(lenh.Value), IntPtr.Zero, 0);
                if (status == 0)
                {
                    return Encoding.UTF8.GetString(val);
                }
            }
            return null;
        }
        finally
        {
            if (lenh.HasValue)
            {
                lenh.Value.Free();
            }
            if (valh.HasValue)
            {
                valh.Value.Free();
            }
        }
    }

It will properly return from sysctlbyname (with -1 ) when I give it a bogus sysctl property name, like "foobar". However, when I give it a proper name like kern.osrelease , it'll hit that line and freeze and/or crash.

What is wrong and how do I get this to work!?

I know it's not "complete" (I'm sure newp and newlen still need to be modified, but I don't use them anyway), but here is what I did to finally get this to work

[DllImport(MonoTouch.Constants.SystemLibrary)]  
internal static extern int sysctlbyname( [MarshalAs(UnmanagedType.LPStr)] string property, byte[] output, ref Int64 oldLen, IntPtr newp, uint newlen);

public static string SystemStringInfo(string property)
{
    GCHandle? lenh = null, valh = null;
    Int64 len = 0L;

    byte[] val;
    int status = sysctlbyname(property, null, ref len, IntPtr.Zero, 0);
    if (status == 0)
    {

        val = new byte[(Int64) len];
        status = sysctlbyname(property, val, ref len, IntPtr.Zero, 0);
        if (status == 0)
        {
            return Encoding.UTF8.GetString(val);
        }
    }
    return null;
}

Check out my answer here: https://stackoverflow.com/a/14711348/1134836 . I called sysctlbyname to get the UIDevice information.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM