一个成功传递引用类型参数到非托管环境的例子

在写一些对操作系统依赖性很强的东西时,调用windows API是很经常的。调用API就有托管与非托管交互的问题发生。非托管API返回的对象在托管环境下用IntPtr对象可以接收并传递给其它需要的非托管API,而非托管返回的结构数据可以通过在托管里面定义结构类型来接收使用。但是如果需要把托管下的对象传送给非托管API作为参数,然后再取回,就需要用到GCHandle结构了。

看代码:

  1using System;
  2using System.Threading; 
  3using 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    }

代码是调用了iocp的其中几个api(什么是iocp和为什么这么调用,日后再说),代码里面:
public void PostEvent(object iValue) 和   public object getEvent()两个方法,分别就是把对象传递给非托管和从非托管取回对象的方法。其中比较关键的是GCHandle结构所起的作用。它提供从非托管内存访问托管对象的方法。

就是通过它来完成把托管对象传递给非托管环境的,具体的方法在代码可以很清楚看到。下面是测试代码:

 1static Win32IOCPSample w;
 2public 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
30static 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==nullbreak;
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使用的办法。其它更高版本还没有深入接触。如果谁有其他方法,欢迎分享。

posted on 2008-01-06 00:24  baoli  阅读(302)  评论(0编辑  收藏  举报

导航