惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

W
WeLiveSecurity
T
The Exploit Database - CXSecurity.com
C
CXSECURITY Database RSS Feed - CXSecurity.com
S
Security @ Cisco Blogs
T
Threat Research - Cisco Blogs
TaoSecurity Blog
TaoSecurity Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
腾讯CDC
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
The Blog of Author Tim Ferriss
Microsoft Azure Blog
Microsoft Azure Blog
罗磊的独立博客
F
Full Disclosure
博客园 - 【当耐特】
C
CERT Recently Published Vulnerability Notes
Engineering at Meta
Engineering at Meta
Application and Cybersecurity Blog
Application and Cybersecurity Blog
T
Threatpost
I
Intezer
V2EX - 技术
V2EX - 技术
H
Hackread – Cybersecurity News, Data Breaches, AI and More
The Hacker News
The Hacker News
小众软件
小众软件
Google DeepMind News
Google DeepMind News
T
Tailwind CSS Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
B
Blog RSS Feed
Microsoft Security Blog
Microsoft Security Blog
N
News | PayPal Newsroom
MyScale Blog
MyScale Blog
AI
AI
Vercel News
Vercel News
Spread Privacy
Spread Privacy
美团技术团队
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
The GitHub Blog
The GitHub Blog
V
Vulnerabilities – Threatpost
Schneier on Security
Schneier on Security
Cyberwarzone
Cyberwarzone
G
GRAHAM CLULEY
Help Net Security
Help Net Security
Hacker News: Ask HN
Hacker News: Ask HN
Google DeepMind News
Google DeepMind News
MongoDB | Blog
MongoDB | Blog
L
LINUX DO - 热门话题
U
Unit 42
L
LangChain Blog
Recent Announcements
Recent Announcements

博客园 - Koy

vbox 安装 MacOS 时遇到的问题 转载:登录后,用户配置被修改的处理方法 left join 和 inner join 区别和优化 认识位移操作符 動態修改 XML 欄位 (轉載)sql server xml字段的操作 (轉)CSS 单行溢出文本显示省略号...的方法(兼容IE FF) (轉)Equal height boxes with CSS 獲得瀏覽器顯示標簽的真實的長寬高 轉:Jquery绑定img的click事件 SqlLocalDB 的一些常用命令行 转:css实现强制不换行/自动换行/强制换行 終于解決调用wordpress 4.3 xmlrpc api 发布包含分类的文章时返回“抱歉,文章类型不支持您的分类法”错误的問題 SQL 數字欄位格式調整(輸出結果以0補至固定長度) ajax 維護 div 的 scrollbar 每日构建的好工具 修正了Flex Tree 控件在動態加載節點后 Scrollbar 沒有立即出現的問題 根據基本目錄及文件的全路逕,創建相應的子目錄,爲保存文件作準備 - Koy - 博客园 轉載:Sqlserver 2005 利用 with 創建臨時表進行遞歸查詢
转载:数组Marshalling
Koy · 2012-04-08 · via 博客园 - Koy

2012-04-08 21:35  Koy  阅读(203)  评论()    收藏  举报

在托管代码和本地代码之间传递数组,是interop marshaling中间比较复杂的一个问题。本文从数组的定义开始,介绍数组marshalling的三种方法,并对blittable类型等概念做进一步的讨论。


当托管代码需要和本地代码互操作时,我们就进入了interop的领域。interop的场景形形色色,不变的是我们需要把数据从一个世界marshal到另一个世界。


在讨论数组marshalling之前,请各位和我一起思考一个问题,什么是数组?之所以要讨论这个问题,原因在于不同的术语在不同的语境中含有不同的意思。在使用c语言的时候,我认为数组就是一个指针。但是熟悉c#的朋友可能不同意我的观点,数组是System.Array或者Object[]。我认为,这两种回答都是出自语言领域的正确观点。那么如果有一个项目含有两个模块,一个用本地代码撰写,另一个用托管代码撰写,两者之间的接口要求传递一个数组,这个”数组”包含着怎样的语义呢?我觉得有两点是很重要的:


1. 如何访问数组元素。就好比c语言中的数组指针,c#中的数组引用,都是访问数组必不可少的线索。 
2. 数组的大小。数组的大小不仅仅是System.Array.Length。它还可以包括诸如数组的维数,每个维上的启始边界和结束边界。


.NET在marshal数组的时候,很大程度上也是从以上两点出发,架起托管世界和本地代码之间的桥梁。根据操作的具体数据类型不同,数组marshal又可以分为以下两个大类,三个小类,我们分别介绍:


1. 数组作为参数传递 
a) c/c++类型的数组 
c类型的数组,也就是由指针指明存储空间首地址的数组,是一个自描述很低的数据结构。尽管有些编译器支持在固定偏移量上写入数组的长度,但是因为各个编译器处理的具体方法不同,没有一个标准让CLR来参考。所以我们在marshal一个c类型的数组的时候,不得不用其他方法考虑传递数组的大小,有以下两种:

1) 约定指针数组长度 
这种方法需要调用者和被调用者之间有一个约定,给出一个数组长度的固定值。在托管端声明一个interop方法的时候,只需要用SizeConst这个属性,把这个约定告诉CLR。CLR在进行Marshal的时候,会根据这个值,在本地堆上分配相应的空间。

public static extern void Ex( 
[In, Out][MarshalAs(UnmanagedType.LPArray, SizeParamConst=3)]string[] a);


2)通过一个额外的参数指定数组长度 
可能有的朋友觉得,约定一个静态的数组长度还不够灵活,希望能够动态的传递数组的长度,从而使得数组marshalling不必受制于固定数组长度的限制。我们先来看普通的函数调用是如何解决这个问题的:caller和callee通过约定一个额外的参数,来传递数组的长度,这可以被视作是一个调用者和被调用者的约定。由于marshalling需要clr的参与,那么就需要把这个约定用clr能够理解的方式,进行扩充,形成一个三方约定。CLR,用属性SizeParamIndex来描述此类约定。

public static extern void Ex2( 
[In, Out][MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]string[] a, 
int len);


b) SafeArray 
SafeArray是COM引入的数据类型,是一个自描述度很高的数据结构。他可以很清楚的告诉用户,该数组的元素类型,数组包含了多少维,每一维的起始位置和终止位置。所以marshal这类safearray的时候,只需要通过设定属性,告诉CLR,当前array对应的本地代码是safearray即可。举例如下:


public void DumpSafeArrayStringIn(

[In][MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_BSTR)]Object[] array);

大家可以看到,SafeArraySubType可以用来指定数组元素的类型


2. 数组作为字段传递 
很久以来,对于interop,一直有这样的评价,简单数据结构的marshalling其实并不复杂,但是一旦进入了struct或者class这种你中有我,我中有你的层叠数据结构之后,marshalling就成了bug的温床。所以在这里,我们也要提提数组作为struct/class的一个字段的方法。在这里首先要给这个stuct/class加一个限制,是byval。由于这个限制,大家可以想象的出,CLR在marshal的时候,做的事情是类似于浅copy的内存复制,所以对数组marshal的时候,也就只支持固定长度的数组marshal。

public class StructIntArray 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst=4)] 
    public int[] array; 
}


数组作为一种常用的数据结构,各种高级语言都提供了相应的支持,在这些高级语言之间交互操作的时候,数组也是传送集合类型数据的重要结构,希望今天的内容能对大家有所帮助。