解读封送类、结构体和联合体实例

 更新时间:2025年01月07日 09:28:16   作者:C6666888  
本文主要介绍了.NETFramework中类、结构体和联合体的封送处理,包括类通过COM互操作封送为接口、结构体通过StructLayoutAttribute属性指定布局和封送方式,以及联合体通过StructLayout(LayoutKind.Explicit)和FieldOffset特性精确控制内存布局

封送类、结构体和联合体实例

封送类

在.NET Framework中,类是引用类型,而结构体是值类型。对于类而言,它们只能通过COM互操作来封送,并且总是作为接口封送。

当托管类传递给COM时,互操作封送处理器会自动使用COM代理包装该类,并将由代理生成的类接口传递到COM方法调用。

例如:

// 假设有一个非托管的COM接口IDemoInterface
[ComImport]
[Guid("...")]
interface IDemoInterface {
    void DoSomething();
}

// 定义一个实现该接口的托管类
public class ManagedClass : IDemoInterface {
    public void DoSomething() {
        Console.WriteLine("Doing something...");
    }
}

// 在托管代码中创建并传递给非托管代码
var managedInstance = new ManagedClass();
// 这里假设有一个非托管函数接收IDemoInterface类型的参数
NativeMethods.PassToUnmanaged(managedInstance);

这里PassToUnmanaged是一个平台调用(P/Invoke)定义的方法,它负责将ManagedClass对象转换成COM接口指针传递给非托管代码。

封送结构体

结构体作为值类型,在跨平台调用时也需要适当的封送处理。

为了确保结构体成员按照预期的方式被解释,通常会在结构体上应用StructLayoutAttribute属性来指定布局方式。

考虑如下C++定义的结构体:

typedef struct _MYPERSON {
    char* first;
    char* last;
} MYPERSON, *LP_MYPERSON;

C#封送定义可能是这样的:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct MyPerson {
    [MarshalAs(UnmanagedType.LPStr)]
    public string first;
    [MarshalAs(UnmanagedType.LPStr)]
    public string last;
}

这里使用了StructLayout特性指定了顺序布局,并通过MarshalAs特性指定了字符串字段如何被封送。

如果要传递此结构体到非托管代码,则可以像下面这样操作:

[DllImport("PinvokeLib.dll")]
static extern int TestStructInStruct([In] MyPerson2 person2);

// 构建MyPerson实例
var person = new MyPerson { first = "John", last = "Doe" };
// 创建包含person指针的MyPerson2实例
var person2 = new MyPerson2 { person = Marshal.AllocCoTaskMem(Marshal.SizeOf(person)), age = 30 };
// 复制person的内容到分配的非托管内存
Marshal.StructureToPtr(person, person2.person, false);
try {
    // 调用非托管函数
    var result = TestStructInStruct(person2);
} finally {
    // 清理非托管资源
    Marshal.FreeCoTaskMem(person2.person);
}

这段代码展示了如何安全地管理非托管内存,并确保正确地封送结构体给非托管函数。

封送联合体

联合体(Union)允许在同一段内存空间内存储不同类型的数据成员。这意味着任何时候只有一个成员有效。

在C#中表示联合体通常涉及到使用StructLayout(LayoutKind.Explicit)特性以及FieldOffset特性来精确控制成员的位置。

比如,我们有以下C++定义的联合体:

union MYUNION {
    int i;
    double d;
};

C#封送定义可以是:

[StructLayout(LayoutKind.Explicit)]
public struct MyUnion {
    [FieldOffset(0)]
    public int i;
    [FieldOffset(0)]
    public double d;
}

这里使用了Explicit布局模式,所有字段都从偏移量0开始,意味着它们共享相同的内存位置。

当需要传递这个联合体到非托管代码时,可以直接使用上述定义,因为.NET运行时知道如何正确地封送联合体中的成员。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • C#中委托和事件在观察者模式中的应用实例

    C#中委托和事件在观察者模式中的应用实例

    这篇文章主要介绍了C#中委托和事件在观察者模式中的应用,需要的朋友可以参考下
    2014-08-08
  • C#调用RabbitMQ实现消息队列的示例代码

    C#调用RabbitMQ实现消息队列的示例代码

    这篇文章主要介绍了C#调用RabbitMQ实现消息队列的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • C#中FTP常用操作的示例代码

    C#中FTP常用操作的示例代码

    这篇文章主要为大家详细介绍了C#中FTP常用操作的相关知识,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以跟随小编一起学习一下
    2024-04-04
  • C#中如何将MongoDB->RunCommand结果映射到业务类的方法总结

    C#中如何将MongoDB->RunCommand结果映射到业务类的方法总结

    这篇文章主要给大家总结介绍了关于C#中如何将MongoDB->RunCommand结果映射到业务类的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2018-04-04
  • C# 使用WPF 用MediaElement控件实现视频循环播放

    C# 使用WPF 用MediaElement控件实现视频循环播放

    在WPF里用MediaElement控件,实现一个循环播放单一视频的程序,同时可以控制视频的播放、暂停、停止。这篇文章给大家介绍了C# 使用WPF 用MediaElement控件实现视频循环播放,需要的朋友参考下吧
    2018-04-04
  • C#调用打印机实现打印

    C#调用打印机实现打印

    这篇文章介绍了C#调用打印机实现打印的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04
  • 使用C#更改PowerPoint幻灯片大小的示例代码

    使用C#更改PowerPoint幻灯片大小的示例代码

    更改幻灯片大小是保持 PowerPoint 演示文稿视觉完整性的一种方式,在本文中,您将学习如何使用 Spire.Presentation for .NET 在 C# 中更改 PowerPoint 演示文稿的幻灯片大小,需要的朋友可以参考下
    2025-12-12
  • C#主线程堵塞问题的解决方案

    C#主线程堵塞问题的解决方案

    这篇文章主要介绍了C#主线程堵塞问题的解决方案,在C#中,异步方法和async/await关键字是用来解决主线程阻塞的有效方式,文中有相关的代码示例供大家参考,需要的朋友可以参考下
    2024-03-03
  • C# 设计模式系列教程-抽象工厂模式

    C# 设计模式系列教程-抽象工厂模式

    抽象工厂模式为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。
    2016-06-06
  • C#通过ADO.NET访问数据的方法详解

    C#通过ADO.NET访问数据的方法详解

    在 C# 的应用开发中,数据访问是极为关键的部分,ADO.NET作为.NET 框架下用于数据访问的核心技术,能够帮助开发者便捷地与各类数据源进行交互,本文将深入剖析ADO.NET,带你掌握使用 C# 通过ADO.NET访问数据的方法,需要的朋友可以参考下
    2025-02-02

最新评论