ZT: .NET Interop入門-P/Invoke和Reverse P/Invoke 

文章內容

最近在論壇上經常看到一些基本的interop的問題,給我動力寫完之前的.net interop入門系列,給剛剛涉足.NET interop的朋友們一個大體上的概念。

每每談及.NET interop,我的腦中總是出現下面一幅圖:



該圖代表了.net interop的四個典型場景。之前我的同事和我討論了.NET和COM互操作的應用:

* 在.NET中調用COM:COM Interop入門
* 在COM中調用.NET:在COM應用中使用.NET組件使用IDispatch::Invoke函數在C++中調用C#實現的托管類庫方法

今天我主要講一下P/Invoke和Reverse P/Invoke,和COM interop相比,P/Invoke無需注冊組件,使用上更輕量,更綠色。

1. P/Invoke

P/Invoke(platform invoke)是.NET調用本地代碼(native code)的一種比較輕便的方式。只需要將本地代碼編寫成動態鏈接庫,然後在c#代碼中,聲明一個外部靜態函數,並且用DllImport屬性指明動態連接庫的入口。舉例如下:

代碼:
using System;
using System.Runtime.InteropServices;

class PInvoke
{
    [DllImportAttribute("user32.dll", EntryPoint = "MessageBoxW")]
    public static extern  int MessageBoxW(
        [In]System.IntPtr hWnd,
        [In][MarshalAs(UnmanagedType.LPWStr)] string lpText,
        [In][MarshalAs(UnmanagedType.LPWStr)] string lpCaption,
        uint uType);

    public static void Main()
    {
        MessageBoxW(IntPtr.Zero, "Hello", "Interop", 0);
    }
}

稍加解釋這個代碼。類PInvoke中,有個MessageBoxW的函數聲明,它的實現在user32.dll(系統自帶)中,入口是MessageBoxW,參數的構成是根據windows API的聲明而定的,我們在Codeplex上有一個工具,專門幫助大家聲稱一個本地代碼(c++)編寫的函數在托過代碼(c#)中的函數聲明,之前我們團隊的成員也撰文介紹了這個工具的使用。

有了這個聲明以後,在Main中調用MessageBox,就和調用其他托管代碼一樣輕松自如了。

2. Reverse P/Invoke

接著,我們來看看在本地代碼中調用.NET方法。本地代碼需要拿到一個.NET委托(delegate),然後把這個delegate當作一個函數指針使用,示例如下:

代碼:
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

public class Program
{
    internal delegate void DelegateMessageBox([MarshalAs(UnmanagedType.LPWStr)]string msg);

    [DllImport("Native.dll", CallingConvention = CallingConvention.Cdecl)]
    static extern void NativeMethod(DelegateMessageBox d);

    public static void ShowMessageBox(string msg)
    {
       MessageBox.Show(msg);
    }

    public static void Main()
    {
        NativeMethod(new DelegateMessageBox(ShowMessageBox));
    }
}

這個例子中,我們希望本地代碼能夠調用托管函數ShowMessageBox來顯示一個對話框。為了讓本地代碼可以調用這個函數,我們根據它的聲明,定了了一個delegate,並且通過P/Invoke把這個委托傳給了本地代碼。本地代碼可以如下調用托管代碼:

代碼:
#include <stdio.h>
#include <wtypes.h>

extern "C" {
    __declspec(dllexport) void NativeMethod(void (__stdcall *pShowMsgBox)(WCHAR *wChar))
    {
        (*pShowMsgBox)(L"hello reverse interop");
    }
}


注意到托管代碼中的委托到了本地代碼中,就是一個函數指針,本地代碼可以像一個普通的函數指針一般調用托管代碼。

大家可能注意到dll的聲明用了extern “C”,它指明了調用規范是cdecl,在之前的托過代碼的DllImport中,也相應的注明了調用約定,關於調用約定的詳細介紹,可以參見我的另一篇博客。

今天的介紹就到這裡,大家可以把這些示例代碼當作一個template,根據實際需求作相應的具體改動。

Published Sunday, March 29, 2009 12:24 AM by SilverlightShanghai
Filed under: CLR Interop, .NET小貼士
QR Code
請用微信 掃一掃 掃描上面的二維碼,然後點擊頁面右上角的 ... 圖標,然後點擊 發送給朋友分享到朋友圈,謝謝!
分享:
分享到微信

文章評論

Castro
無題
DING!

2009-04-05 23:19:17 | 引用
無題
不錯。直接到他們的團隊blog上看了看,東西不多不過他們自己開發的一個tool - TlmImp2挺不錯的。可以直接調用COM庫,然後生成Interop Assembly。

2009-06-07 09:54:10 | 引用
nessus
飛舞的音符
Re: ZT: .NET Interop入門-P/Invoke和Reverse P/Invoke
學習中。。。

2009-06-16 23:03:49 | 引用

發表評論

個人簡介

webdriver
『人生游戲,游戲人生』


日志分類
最新日志
此功能已被空間主人關閉
博客搜索
 
快速導航
友情鏈接
此功能已被空間主人關閉
博客統計
點擊: 648907
帖子數量: 691
開辟個人空間: 2008-10-15
最後更新: 2018-05-11
左鄰右舍
 
 
 
 
 
The images, logos, trademarks used on this site and all forwarded content are the property of their respective owners.
We are not responsible for comments posted by our visitors, as they are the property of the poster.
All other content of this website is copyrighted by 加西網

Private Policy | moonlake oblog skin

加西網為北美中文網傳媒集團旗下網站