一个成功传递引用类型参数到非托管环境的例子
在写一些对操作系统依赖性很强的东西时,调用windows API是很经常的。调用API就有托管与非托管交互的问题发生。非托管API返回的对象在托管环境下用IntPtr对象可以接收并传递给其它需要的非托管API,而非托管返回的结构数据可以通过在托管里面定义结构类型来接收使用。但是如果需要把托管下的对象传送给非托管API作为参数,然后再取回,就需要用到GCHandle结构了。
看代码:
代码是调用了iocp的其中几个api(什么是iocp和为什么这么调用,日后再说),代码里面:
public void PostEvent(object iValue) 和 public object getEvent()两个方法,分别就是把对象传递给非托管和从非托管取回对象的方法。其中比较关键的是GCHandle结构所起的作用。它提供从非托管内存访问托管对象的方法。
就是通过它来完成把托管对象传递给非托管环境的,具体的方法在代码可以很清楚看到。下面是测试代码:
整个列子就是这么一回事。这是1.1使用的办法。其它更高版本还没有深入接触。如果谁有其他方法,欢迎分享。
看代码:
1
using System;
2
using System.Threading;
3
using System.Runtime.InteropServices;
4
5
/// <summary>
6
/// Win32IOCPSample 的摘要说明。
7
/// iocp的示范列子,一个成功传递引用类型参数到非托管环境的例子
8
/// </summary>
9
public class Win32IOCPSample
10
{
11
public Win32IOCPSample(int maxThread)
12
{
13
try
14
{
15
// Create an IO Completion Port for Thread Pool use
16
GetHandle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, IntPtr.Zero, maxThread);
17
18
// Test to make sure the IO Completion Port was created
19
if (GetHandle == 0)
20
throw new Exception("Unable To Create IO Completion Port");
21
}
22
catch
23
{
24
throw new Exception("Unhandled Exception");
25
}
26
}
27
28
[DllImport("Kernel32")]
29
private static extern void CloseHandle(UInt32 handle);
30
[DllImport("Kernel32")]
31
private static extern UInt32 CreateIoCompletionPort(UInt32 fileHandle, UInt32 existingCompletionPort,IntPtr completionKey, int numberOfConcurrentThreads);
32
[DllImport("Kernel32")]
33
private static extern bool PostQueuedCompletionStatus(UInt32 completionPort, int numberOfBytesTransferred,IntPtr completionKey, IntPtr overlapped);
34
[DllImport("Kernel32")]
35
private static extern bool GetQueuedCompletionStatus(UInt32 completionPort, ref int numberOfBytes,ref IntPtr completionKey, ref IntPtr overlapped,UInt32 milliseconds);
36
37
private const UInt32 INVALID_HANDLE_VALUE = 0xffffffff;
38
private const UInt32 INIFINITE = 0xffffffff;
39
public static readonly Int32 SHUTDOWN_IOCPTHREAD = 0x7fffffff;
40
public delegate void USER_FUNCTION(object iValue);
41
private UInt32 m_hHandle;
42
private UInt32 GetHandle { get { return m_hHandle; } set { m_hHandle = value; } }
43
44
private Boolean m_bDisposeFlag;
45
46
/// <summary>
47
/// 释放标志
48
/// </summary>
49
private Boolean IsDisposed { get { return m_bDisposeFlag; } set { m_bDisposeFlag = value; } }
50
~Win32IOCPSample()
51
{
52
if (!IsDisposed)
53
Dispose();
54
}
55
56
public void Dispose()
57
{
58
unsafe
59
{
60
// Close the IOCP Handle
61
CloseHandle(GetHandle);
62
}
63
}
64
public object getEvent()
65
{
66
int uiNumberOfBytes=0;
67
object obj=null;
68
try
69
{
70
//声明接收对象的指针
71
IntPtr key=IntPtr.Zero;
72
IntPtr ovp=IntPtr.Zero;
73
74
// Wait for an event
75
//取回对象指针
76
if(GetQueuedCompletionStatus(GetHandle, ref uiNumberOfBytes, ref key, ref ovp, INIFINITE)==true)
77
{
78
79
if(key!=IntPtr.Zero && ovp!=IntPtr.Zero)
80
{
81
//把指针转换会GCHandle对象
82
GCHandle gcKey=(GCHandle)key;
83
GCHandle gcOvp=(GCHandle)ovp;
84
// Was this thread told to shutdown
85
if (ovp!=IntPtr.Zero && gcOvp.Target.ToString().Equals(SHUTDOWN_IOCPTHREAD.ToString()))
86
{
87
gcOvp.Free();
88
gcKey.Free();
89
90
return obj;
91
}
92
//通过GCHandle对象取得其所表示的对象
93
obj=gcOvp.Target;
94
95
gcOvp.Free();
96
gcKey.Free();
97
}
98
}
99
}
100
catch(Exception ex)
101
{
102
throw ex;
103
}
104
return obj;
105
}
106
107
public void PostEvent(object iValue)
108
{
109
try
110
{
111
// Only add work if we are not disposing
112
if (IsDisposed == false)
113
{
114
115
int i=0;
116
//取托管对象的句柄
117
GCHandle gcValue=GCHandle.Alloc(iValue);
118
GCHandle gcKey=GCHandle.Alloc(i);
119
// Post an event into the IOCP Thread Pool
120
//把对象句柄作为参数传递给api
121
PostQueuedCompletionStatus(GetHandle, 4, (IntPtr)gcKey, (IntPtr)gcValue);
122
}
123
}
124
catch (Exception e)
125
{
126
throw e;
127
}
128
catch
129
{
130
throw new Exception("Unhandled Exception");
131
}
132
}
133
}
using System;2
using System.Threading; 3
using System.Runtime.InteropServices; 4

5
/// <summary>6
/// Win32IOCPSample 的摘要说明。7
/// iocp的示范列子,一个成功传递引用类型参数到非托管环境的例子8
/// </summary>9
public class Win32IOCPSample10
{11
public Win32IOCPSample(int maxThread)12
{13
try 14
{ 15
// Create an IO Completion Port for Thread Pool use 16
GetHandle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, IntPtr.Zero, maxThread); 17
18
// Test to make sure the IO Completion Port was created 19
if (GetHandle == 0) 20
throw new Exception("Unable To Create IO Completion Port"); 21
} 22
catch 23
{ 24
throw new Exception("Unhandled Exception"); 25
} 26
}27

28
[DllImport("Kernel32")]29
private static extern void CloseHandle(UInt32 handle);30
[DllImport("Kernel32")]31
private static extern UInt32 CreateIoCompletionPort(UInt32 fileHandle, UInt32 existingCompletionPort,IntPtr completionKey, int numberOfConcurrentThreads);32
[DllImport("Kernel32")]33
private static extern bool PostQueuedCompletionStatus(UInt32 completionPort, int numberOfBytesTransferred,IntPtr completionKey, IntPtr overlapped);34
[DllImport("Kernel32")]35
private static extern bool GetQueuedCompletionStatus(UInt32 completionPort, ref int numberOfBytes,ref IntPtr completionKey, ref IntPtr overlapped,UInt32 milliseconds);36
37
private const UInt32 INVALID_HANDLE_VALUE = 0xffffffff; 38
private const UInt32 INIFINITE = 0xffffffff; 39
public static readonly Int32 SHUTDOWN_IOCPTHREAD = 0x7fffffff; 40
public delegate void USER_FUNCTION(object iValue); 41
private UInt32 m_hHandle; 42
private UInt32 GetHandle { get { return m_hHandle; } set { m_hHandle = value; } } 43

44
private Boolean m_bDisposeFlag; 45

46
/// <summary>47
/// 释放标志48
/// </summary>49
private Boolean IsDisposed { get { return m_bDisposeFlag; } set { m_bDisposeFlag = value; } } 50
~Win32IOCPSample() 51
{ 52
if (!IsDisposed) 53
Dispose(); 54
} 55
56
public void Dispose() 57
{ 58
unsafe 59
{ 60
// Close the IOCP Handle 61
CloseHandle(GetHandle); 62
} 63
} 64
public object getEvent()65
{66
int uiNumberOfBytes=0; 67
object obj=null;68
try 69
{ 70
//声明接收对象的指针71
IntPtr key=IntPtr.Zero;72
IntPtr ovp=IntPtr.Zero;73
74
// Wait for an event 75
//取回对象指针76
if(GetQueuedCompletionStatus(GetHandle, ref uiNumberOfBytes, ref key, ref ovp, INIFINITE)==true)77
{ 78

79
if(key!=IntPtr.Zero && ovp!=IntPtr.Zero)80
{81
//把指针转换会GCHandle对象82
GCHandle gcKey=(GCHandle)key;83
GCHandle gcOvp=(GCHandle)ovp;84
// Was this thread told to shutdown 85
if (ovp!=IntPtr.Zero && gcOvp.Target.ToString().Equals(SHUTDOWN_IOCPTHREAD.ToString())) 86
{87
gcOvp.Free();88
gcKey.Free();89

90
return obj;91
}92
//通过GCHandle对象取得其所表示的对象93
obj=gcOvp.Target;94

95
gcOvp.Free();96
gcKey.Free();97
}98
}99
}100
catch(Exception ex)101
{102
throw ex;103
}104
return obj;105
}106

107
public void PostEvent(object iValue) 108
{ 109
try 110
{ 111
// Only add work if we are not disposing 112
if (IsDisposed == false) 113
{ 114
115
int i=0;116
//取托管对象的句柄117
GCHandle gcValue=GCHandle.Alloc(iValue);118
GCHandle gcKey=GCHandle.Alloc(i);119
// Post an event into the IOCP Thread Pool 120
//把对象句柄作为参数传递给api121
PostQueuedCompletionStatus(GetHandle, 4, (IntPtr)gcKey, (IntPtr)gcValue); 122
} 123
} 124
catch (Exception e) 125
{ 126
throw e; 127
} 128
catch 129
{ 130
throw new Exception("Unhandled Exception"); 131
} 132
} 133
}代码是调用了iocp的其中几个api(什么是iocp和为什么这么调用,日后再说),代码里面:
public void PostEvent(object iValue) 和 public object getEvent()两个方法,分别就是把对象传递给非托管和从非托管取回对象的方法。其中比较关键的是GCHandle结构所起的作用。它提供从非托管内存访问托管对象的方法。
就是通过它来完成把托管对象传递给非托管环境的,具体的方法在代码可以很清楚看到。下面是测试代码:
1
static Win32IOCPSample w;
2
public static void Main(string[] args)
3
{
4
5
w=new Win32IOCPSample(2);
6
7
for(int i=0; i<5;i++)
8
{
9
Thread t=new Thread(new ThreadStart(worker));
10
t.IsBackground=true;
11
t.Start();
12
}
13
14
for(int i =1;i<20;i++)
15
{
16
w.PostEvent(ExTimer.GetExactNow());
17
}
18
19
for(int i =0;i<5;i++)
20
{
21
w.PostEvent(Win32IOCPSample.SHUTDOWN_IOCPTHREAD);
22
}
23
Thread.Sleep(100);
24
25
26
Console.ReadLine();
27
w.Dispose();
28
}
29
30
static public void worker()
31
{
32
while(true)
33
{
34
try
35
{
36
object obj=w.getEvent();
37
38
Console.Write(qp.Duration(1).ToString()+"\r\n");
39
if(obj==null) break;
40
41
Console.WriteLine("Value: {0}", obj.ToString());
42
43
Thread.Sleep(500);
44
}
45
catch(Exception ex)
46
{
47
Console.WriteLine("ex: {0}", ex.ToString());
48
}
49
}
50
}
static Win32IOCPSample w;2
public static void Main(string[] args) 3
{ 4
5
w=new Win32IOCPSample(2);6

7
for(int i=0; i<5;i++)8
{9
Thread t=new Thread(new ThreadStart(worker));10
t.IsBackground=true;11
t.Start();12
}13
14
for(int i =1;i<20;i++) 15
{ 16
w.PostEvent(ExTimer.GetExactNow()); 17
} 18

19
for(int i =0;i<5;i++) 20
{ 21
w.PostEvent(Win32IOCPSample.SHUTDOWN_IOCPTHREAD);22
}23
Thread.Sleep(100); 24

25

26
Console.ReadLine();27
w.Dispose(); 28
} 29

30
static public void worker()31
{32
while(true)33
{34
try35
{36
object obj=w.getEvent();37

38
Console.Write(qp.Duration(1).ToString()+"\r\n");39
if(obj==null) break;40

41
Console.WriteLine("Value: {0}", obj.ToString()); 42

43
Thread.Sleep(500);44
}45
catch(Exception ex)46
{47
Console.WriteLine("ex: {0}", ex.ToString()); 48
}49
}50
}整个列子就是这么一回事。这是1.1使用的办法。其它更高版本还没有深入接触。如果谁有其他方法,欢迎分享。

浙公网安备 33010602011771号