中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 看雪学院专区 > Win32/Win64编程
让我们一起学Metadata API(2)
作者:tankaiha 时间:2006-12-15 15:46 出处:pediy.com 责编:月夜寒箫
              摘要:让我们一起学Metadata API(2)
让我们一起学MetaData API(2)
    上次简单地介绍了在win32下使用MetaData API的方法,本章在深入应用它的各种功能前,先介绍在C# 下运用的方法。因为C#用于.net编程实在是太方便了!本章的示例代码来自开源软件DILE(dotnet il editor),下载地址http://dile.sourceforge.net。
1、  在C#中引入COM
    C#中使用COM要用到.net与COM的Interop,所有的内容全部都是公开的,所以直接看代码。一般,需要引用什么接口,就建立一个相应的文件,比如要引用IMetaDataDispenserEx接口,我们就在工程中新建一个IMetaDataDispenserEx.cs,代码如下(代码引用自我写的injectReflector):

namespace injectReflector.com
{
    [ComImport, GuidAttribute("31BCFCE2-DAFB-11D2-9F81-00C04F79A0A3"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IMetaDataDispenserEx
    {
        uint DefineScope(ref Guid rclsid, uint dwCreateFlags, ref Guid riid, [MarshalAs(UnmanagedType.Interface)]out object ppIUnk);
        uint OpenScope([MarshalAs(UnmanagedType.LPWStr)]string szScope, uint dwOpenFlags, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppIUnk);

        uint OpenScopeOnMemory(IntPtr pData, uint cbData, uint dwOpenFlags, ref Guid riid, [MarshalAs(UnmanagedType.Interface)]out object ppIUnk);

        uint SetOption(ref Guid optionid, [MarshalAs(UnmanagedType.Struct)]object value);

        uint GetOption(ref Guid optionid, [MarshalAs(UnmanagedType.Struct)]out object pvalue);

        uint OpenScopeOnITypeInfo([MarshalAs(UnmanagedType.Interface)]ITypeInfo pITI, uint dwOpenFlags, ref Guid riid, [MarshalAs(UnmanagedType.Interface)]out object ppIUnk);

        uint GetCORSystemDirectory([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]char[] szBuffer, uint cchBuffer, out uint pchBuffer);

        uint FindAssembly([MarshalAs(UnmanagedType.LPWStr)]string szAppBase, [MarshalAs(UnmanagedType.LPWStr)]string szPrivateBin, [MarshalAs(UnmanagedType.LPWStr)]string szGlobalBin, [MarshalAs(UnmanagedType.LPWStr)]string szAssemblyName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)]char[] szName, uint cchName, out uint pcName);

        uint FindAssemblyModule([MarshalAs(UnmanagedType.LPWStr)]string szAppBase, [MarshalAs(UnmanagedType.LPWStr)]string szPrivateBin, [MarshalAs(UnmanagedType.LPWStr)]string szGlobalBin, [MarshalAs(UnmanagedType.LPWStr)]string szAssemblyName, [MarshalAs(UnmanagedType.LPWStr)]string szModuleName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5)]char[] szName, uint cchName, out uint pcName);
    }
}

    关键的几处,一是ComImport属性中的定义,包话GUID值和接口类型(IUnknown),这样我们的接口就定义OK了。随后就是在接口中定义COM中的所有函数,由于是Interface,所以这里的定义中不包含任何代码。

2、  C#中使用本地数据类型
    接口函数的定义中用到了许多MarshalAs,这是C#与本地数据类型的转换。《COM本质论》中给出了一张表,列举了所有的需要转换和C#自动转换的数据类型。看下代码中用到的:
无需转换:uint、Guid
需要转换:
object  [MarshalAs(UnmanagedType.Interface)]
object  [MarshalAs(UnmanagedType.Struct)]
string  [MarshalAs(UnmanagedType.LPWStr)]
char[]  [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5或4)]

    其中string的转换也许是最常用的,特别是在调用本地dll时。指针倒反而简单了,IntPtr直接使用。

3、  使用Interface
    定义完接口后,在代码中如何使用呢?首先要定义这些接口的变量:
    public static IMetaDataDispenserEx dispenser;
    public static IMetaDataImport import;
    随后就可以直接使用接口的方法。看下示例,同样来自injectReflector中:

        public static string GetMethodDefName(uint token)
        {
            string szRet;
            uint bclass=0;
            char[] szName=new char[MAX_NAME_LENGTH];
            uint ccount;
            uint pAttr;
            IntPtr pBlob;
            uint bcount;
            uint pRVA;
            uint flags;

            import.GetMethodProps(token, out bclass, szName, (uint)MAX_NAME_LENGTH, out ccount, out pAttr, out pBlob, out bcount, out pRVA, out flags);
            if(ccount==0)
            {
                szRet = token.ToString();
            }
            else
            {
                szRet = new string(szName, 0, Convert.ToInt32(ccount) - 1);
            }

            if(bclass!=0)
            {
                szRet = GetTypeDefRefName(bclass) +"."+ szRet;
            }
            return szRet;
        }

     这段代码是根据一个token取得该token所对应的方法的名称。值得注意的仍然是类型的转换,看下IMetaDataImport::GetMethodProps的原型定义:
   HRESULT GetMethodProps (
        mdMethodDef         mb, 
        mdTypeDef           *pClass, 
        LPWSTR              szMethod, 
        ULONG               cchMethod, 
        ULONG               *pchMethod,
        DWORD               *pdwAttr, 
        PCCOR_SIGNATURE     *ppvSigBlob, 
        ULONG               *pcbSigBlob, 
        ULONG               *pulCodeRVA, 
        DWORD               *pdwImplFlags
    );
    对照代码可以看到uint代替了大多数定义,包括mdMethodDef、mdTypeDef、ulong、dword,还有两个转换是LPWSTR就直接传递char[],指针PCCOR_SIGNATURE直接用IntPtr代替。所有的MetaData接口用到的类型基本上就这么多了。
    最后,需要使用哪个接口的某个方法,就直接用C#的语法进行调用:
import.GetMethodProps
import.GetFieldProps
import.GetTypeSpecFromToken

4、  小结
    完整的代码示例请参照开始给出的DILE。本文没有什么难度,只是介绍下C#中使用MetaData COM接口的方法,但是MetaData API的威力确是无穷的。以后有时间再介绍吧。



关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有