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

推荐订阅源

IT之家
IT之家
Recent Announcements
Recent Announcements
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The GitHub Blog
The GitHub Blog
MyScale Blog
MyScale Blog
爱范儿
爱范儿
GbyAI
GbyAI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
美团技术团队
Y
Y Combinator Blog
博客园 - 叶小钗
Apple Machine Learning Research
Apple Machine Learning Research
Martin Fowler
Martin Fowler
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
罗磊的独立博客
M
MIT News - Artificial intelligence
博客园 - Franky
V
Visual Studio Blog
I
InfoQ
V
V2EX
Hugging Face - Blog
Hugging Face - Blog
腾讯CDC
博客园 - 司徒正美
L
LangChain Blog

博客园 - wuhang

今天看到一个好的WEB进度条,博客园果然是富饶啊,先记录下来以备后用 c#后台写javascript前端调用 动态SQL语句根据数据库列来查询数据,动态的生成列名称 asp.net的自动跳转 【转载来的】关于句柄的一些知识 [转载来的]C# API 大全 [心情日記]亦夢亦幻 [转载来的]P/Invoke使用Win32非托管函数2 [转载来的]P/Invoke使用Win32非托管函数3 [转载来的]P/Invoke使用Win32非托管函数1 转载来的WCF基础知识问与答 转载来的,线程的基础 转载来的线程池 转载来的WinForm多线程编程篇 还是转载的C# 插件构架实战 依旧是转载来的Thread and Sync In C# (C#中的线程与同步) 转载来的C# 2.0中P/Invoke支持的几处增强 还是转载来的P/Invoke使用Win32非托管函数 转载来的P/Invoke调用,来自MSDN
【转载来的】C# 2.0中P/Invoke支持的几处增强
wuhang · 2008-05-29 · via 博客园 - wuhang

1、Array in stack

对于这样的struct:typedef struct { int XY[2]; } Point2D;

要在.NET为一个非托管函数传递这样一个结构体,原来得这样定义:

struct Point2D
{
 [MarshalAs(UnmanagedType.ByValArray, SizeConst=2)]
 public int[] XY;
}

  现在可以这么写(不过得用unsafe上下文):

unsafe struct Point2D
{
public fixed int XY[2];
}

 

不过这个功能还非常有限,不知道是出于什么原因考虑,只允许在strcut里面定义这样的数组,并且只能使用bool, byte,  short, int, long, char, sbyte, ushort, uint, ulong, float和double这样的 primitive类型。

也可以把数组作为局部变量分配在堆栈上,只是语法不太一样,那就是stackalloc关键字:int* fib = stackalloc int[100];,也要unsafe上下文。这可以提高不少效率。这是.NET 1.x就有的功能,只是似乎没人用这个

PS. 对于只允许使用primitive类型,我认为是没道理的,最起码应该允许所有值类型的栈内数组。设计者们为啥这么考虑呢?怕堆栈溢出?据我测试.NET的堆栈空间也是1M左右,大部分情况下这么大的栈空间都被浪费了。

2、Function pointer as a return value

在.NET 1.x做P/Invoke时,对于那些回调函数,可以使用Delegate类型的参数作为函数指针传入。但有些非托管函数的返回值也是个函数指针,此时.NET 1.1变得无能为力,要调用这个函数,你得用native代码再写个包装,总之很麻烦。

.NET 2.0的System.Runtime.InteropServices.Marshal类为此需求新增了两个方法:

public static Delegate GetDelegateForFunctionPointer (
IntPtr ptr,
Type t
);

public static IntPtr GetFunctionPointerForDelegate (
Delegate d
);

3、Marshal过程支持更多的类型

这是一个很细的问题,比如这样一个非托管struct:

typedef struct { Point2D XYZ[3]; } Point2DX3;

struct Point2D
{
 [MarshalAs(UnmanagedType.ByValArray, SizeConst=2)]
 public int[] XY;
}

struct Point2DX3
{
 [MarshalAs(UnmanagedType.ByValArray, SizeConst=3)]
 public Point2D[] XYZ;
}

  事实上这是不可行的。在.NET 1.x,结构体内嵌定长数组的类型必须是primitive类型,否则不能进行marshal过程。事实上调用Marshal.SizeOf时,会弹出异常说“无法得到大小”云云

.NET 2.0把这个问题给改了(与其说是个增强,还不如说是修正了这个bug),Marshal.SizeOf(typeof(Point2DX3))现在可以正常运行,输出24 == 3 * 2 * sizeof(int)。

让Marshal.SizeOf正常工作非常重要,得不到对象的大小,内存对齐都无法保证,marshal过程根本就不可行。

此外,正常工作的Marshal.SizeOf可以使这种“序列化”方式也总能正常工作(这在我以前的blog贴过,这里是Generic版本):

unsafe class BinarySerializer
{
public static byte[] Struct2Bytes<T>(T obj)
{
int size = Marshal.SizeOf(obj);
byte[] bytes = new byte[size];
fixed (byte* pb = &bytes[0])
{
Marshal.StructureToPtr(obj, (IntPtr)pb, true);
}
return bytes;
}

public static T Bytes2Struct<T>(byte[] bytes)
{
fixed (byte* pb = &bytes[0])
{
return (T)Marshal.PtrToStructure((IntPtr)pb, typeof(T));
}
}
}

和.NET内置的序列化机制相比,这个方案效率要高得多。和.NET内置的序列化机制相似,这里需要对象或结构体内部的所有成员都能使用 Marshal.SizeOf得到其大小,对应于“对象或结构体内部的所有成员都带有[Serializable]特性或者实现了 ISerializable接口”。

PS. 这个序列化方案效率虽高,但不如.NET内置的方案可靠。.NET的编译器可以检查一个 类型能否支持序列化,而这个方案得由程序员判断Marshal.SizeOf能否工作(比如Marshal.SizeOf绝对不会知道string类型实 际占用多少内存,也就是说类型实例的大小必须是固定的才行)。