当前位置: 代码网 > it编程>编程语言>C# > 解读封送类、结构体和联合体实例

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

2025年02月14日 C# 我要评论
封送类、结构体和联合体实例封送类在.net framework中,类是引用类型,而结构体是值类型。对于类而言,它们只能通过com互操作来封送,并且总是作为接口封送。当托管类传递给com时,互操作封送处

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

封送类

在.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运行时知道如何正确地封送联合体中的成员。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com