Example #1
0
        /// <summary>
        /// Marshal a managed object to an unmanaged chunk of memory. If <paramref name="structure"/> is not CustomMarshalable this
        /// function is the same as <see cref="Marshal.StructureToPtr"/>.
        /// </summary>
        /// <param name="structure">A managed object to marshal to unmanaged memory.</param>
        /// <param name="ptr">Pointer to unmanaged memory. This must be allocated before call</param>
        /// <param name="fDeleteOld">Indicates whether to delete old memory first</param>
        public static void StructureToPtr(object structure, IntPtr ptr, bool fDeleteOld)
        {
            if (!IsCustomMarshalObject(structure))
            {
                Marshal.StructureToPtr(structure, ptr, fDeleteOld);
                return;
            }

            // first check that the struct has the struct layout attribute
            StructLayoutAttribute sla = structure.GetType().StructLayoutAttribute;

            if (sla.IsDefaultAttribute() || sla.Value == LayoutKind.Auto)
            {
                throw new ArgumentException("Structure must have StructLayoutAttribute with LayoutKind Explicit or Sequential", "structure");
            }

            // iterate through all struct fields, handling customs, and using Marshal.StructToPtr for others
            uint extraDataOffset = 0;
            uint structBase      = (uint)ptr.ToInt32();
            uint structSize      = (uint)Marshal.SizeOf(structure);

            foreach (FieldInfo field in structure.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance))
            {
                uint fieldLoc = structBase + (uint)Marshal.OffsetOf(structure.GetType(), field.Name);
                if (field.IsDefined(typeof(CustomMarshalAsAttribute), true))
                {
                    byte[] bytes;
                    CustomMarshalAsAttribute attr = (CustomMarshalAsAttribute)(field.GetCustomAttributes(typeof(CustomMarshalAsAttribute), true)[0]);
                    switch (attr.Value)
                    {
                    case CustomUnmanagedType.LPStr:
                        string val = (string)field.GetValue(structure) + '\0';
                        bytes = Encoding.ASCII.GetBytes(val);
                        break;

                    case CustomUnmanagedType.LPWStr:
                        val   = (string)field.GetValue(structure) + '\0';
                        bytes = Encoding.Unicode.GetBytes(val);
                        break;

                    default:
                        throw new NotSupportedException("Operation not yet supported");
                    }
                    uint dataLoc = structBase + structSize + extraDataOffset;
                    Marshal.WriteIntPtr(new IntPtr(fieldLoc), new IntPtr(dataLoc));
                    // write the raw bytes to dataLoc
                    for (int i = 0; i < bytes.Length; i++, extraDataOffset++)
                    {
                        Marshal.WriteByte(new IntPtr(dataLoc + (uint)i), bytes[i]);
                    }
                }
                else
                {
                    Marshal.StructureToPtr(field.GetValue(structure), new IntPtr(fieldLoc), fDeleteOld);
                }
            }
        }
Example #2
0
        /// <summary>
        /// Marshal an unmanaged to pointer to a managed object. If <paramref name="structureType"/> is not CustomMarshalable, this
        /// function is the same as <see cref="Marshal.StructureToPtr"/>.
        /// </summary>
        /// <param name="ptr">Pointer to unmanaged memory</param>
        /// <param name="structureType">Type of managed object to instantiate</param>
        /// <returns>Managed instance of <paramref name="structureType"/> type</returns>
        public static object PtrToStructure(IntPtr ptr, Type structureType)
        {
            if (ptr == IntPtr.Zero)
            {
                return(null);
            }
            if (structureType == null)
            {
                throw new ArgumentNullException("structureType");
            }
            if (structureType.IsGenericType)
            {
                throw new ArgumentException("Structure type must be non-generic", "structureType");
            }

            if (!IsCustomMarshalType(structureType))
            {
                return(Marshal.PtrToStructure(ptr, structureType));
            }

            StructLayoutAttribute sla = structureType.StructLayoutAttribute;

            if (sla.IsDefaultAttribute() || sla.Value == LayoutKind.Auto)
            {
                throw new ArgumentException("Structure must have StructLayoutAttribute with LayoutKind Explicit or Sequential", "structure");
            }

            object structure = Activator.CreateInstance(structureType);

            uint structBase = (uint)ptr.ToInt32();
            uint structSize = (uint)Marshal.SizeOf(structure);

            foreach (FieldInfo field in structureType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance))
            {
                uint fieldLoc = structBase + (uint)Marshal.OffsetOf(structureType, field.Name);
                if (field.IsDefined(typeof(CustomMarshalAsAttribute), true))
                {
                    IntPtr extraDataLoc = Marshal.ReadIntPtr(new IntPtr(fieldLoc));

                    CustomMarshalAsAttribute attr = (CustomMarshalAsAttribute)(field.GetCustomAttributes(typeof(CustomMarshalAsAttribute), true)[0]);
                    switch (attr.Value)
                    {
                    case CustomUnmanagedType.LPStr:
                        field.SetValue(structure, Marshal.PtrToStringAnsi(extraDataLoc));
                        break;

                    case CustomUnmanagedType.LPWStr:
                        field.SetValue(structure, Marshal.PtrToStringUni(extraDataLoc));
                        break;

                    default:
                        throw new NotSupportedException("Operation not currently supported");
                    }
                }
                else
                {
                    field.SetValue(structure, Marshal.PtrToStructure(new IntPtr(fieldLoc), field.FieldType));
                }
            }
            return(structure);
        }