zoukankan      html  css  js  c++  java
  • 摘录:CSharp调用C动态链接库详解

           第一篇编译C的动态连接库

    在实际工作中,我们经常会将C语言中的.lib和.h文件(静态库)编译成动态连接库.dll文件(这里只提供这两种文件,没有完整的工程),以提供给其他语言平台调用。

    1,必须有.lib文件,只有.h文件是无法编译动态连接库的。

    2,我使用的是VS2008,这里打开VS,新建项目—〉win32控制台应用程序,输入项目名称,点击确定,图示如fig.1所示。

                           

                                 Fig.1

    3,点击下一步,依次如图fig.2-3所示,最后点击完成,就会生成一个带有.cpp的文件。

                                 Fig.2

      

                                    Fig.3

    4,打开项目—属性—配置属性—链接器—输入,如下图fig.4所示,在附加依赖项中加入你要添加的.lib文件,如果有一些系统.lib库没有添加或出现错误,可以在忽略特定库中添加该库。

    注意:如果编译的dll文件调用中出现“xx.dll中找不到函数xx的入口点”,很有可能是一个xx.def文件没有添加,该文件的内容是EXPORTS  函数名@+序号。如果这个文件中没有你要调用的API 函数,那么你在C#中是调用不到这个函数的,同时这个文件你可以同坐记事本自己编辑,注意!!!

                                 Fig.4

    5,在.cpp文件中添加.h文件的引用,不需要把所有的.h文件都引用进去,只需要.lib文件入口相关的.h文件。

    6,最后把.lib和.h文件拷贝到工程debug目录里,生成解决方案就Ok了,你会发现.dll在debug目录中出现。

       第二篇C#调用C/C++的动态连接库

    1,清楚C++与C#类型对应关系,即调用关系:

    C基本类型对照关系----VS2008:

    除此之外,

    c++:HANDLE(void *) ---- c#:System.IntPtr

    c++:WORD(unsigned short) ---- c#:System.UInt16

    c++:DWORD(unsigned long) ---- c#:System.UInt32

    c++:结构体 ---- c#:public struct 结构体{};

    c++:结构体 &变量名 ---- c#:ref 结构体 变量名

    c++:结构体 **变量名 ---- c#:out

    c++:GUID ---- c#:Guid

    c++:UINT8 * ---- c#:ref byte

    c++:char*/void*(指向一个字符串) ---- c#:string

    对于结构体中的指针数组,对应于C#中的IntPtr[]类型,如:   

    int * a[] -------------- IntPtr[]a

    2,清楚在C#中调用C/C++.dll文件的一般格式

    using System.Runtime.InteropServices; //必须引用的命名空间

    [DllImport("user32.dll")]
    public static extern ReturnType FunctionName(type arg1,type arg2,...);

    //必须定义为类的静态外部的方法

    3,[DllImport(参数)]设定

    ①“xx.dll” :dll文件名字

    ②CharSet :控制调用函数的名称版本及指示如何向方法封送 String 参数。如果 CharSet 字段设置为 Unicode,则所有字符串参数在传递到非托管实现之前都转换成 Unicode 字符。这还导致向 DLL EntryPoint 的名称中追加字母“W”。如果此字段设置为 Ansi,则字符串将转换成 ANSI 字符串,同时向 DLL EntryPoint 的名称中追加字母“A”。

    EntryPoint 指示要调用的 DLL 入口点的名称或序号。如果你想使用自己定义的函数名字fucXX,则:”EntryPoint=fucXX”。

    ③ExactSpelling:指示是否应修改非托管 DLL 中的入口点的名称,以与 CharSet 字段中指定的 CharSet 值相对应。如果为 true,则当 DllImportAttribute.CharSet 字段设置为 CharSet 的 Ansi 值时,向方法名称中追加字母 A,当 DllImportAttribute.CharSet 字段设置为 CharSet 的 Unicode 值时,向方法的名称中追加字母 W。此字段的默认值是 false。

    ④PreserveSig:指示托管方法签名不应转换成返回 HRESULT、并且可能有一个对应于返回值的附加 [out, retval] 参数的非托管签名。

    ⑤SetLastError:指示被调用方在从属性化方法返回之前将调用 Win32 API SetLastError。 true 指示调用方将调用 SetLastError,默认为 false。

    4,具体实例

    C中API函数:

    Unsigned long int Fuc (int a,void* b);

    C#中定义:

    [DllImport("testall.dll", ExactSpelling = false)]

    public extern static UInt32 Fuc(int a, IntPtr b);//

    C中结构体:

    #define M 3

    typedef struct __tag_MBITMAP{

    DWord dwPixelArrayFormat;

    Long lWidth;

    Long lHeight;

    Long lPitch[MPAF_MAX_PLANES];

    Byte* pPlane[MPAF_MAX_PLANES];

    }BITMAP

    C#定义:

           [StructLayout(LayoutKind.Sequential)] //此句在C#中重新定义结构体时一定要加上

            public struct BITMAP

            {

                [MarshalAs(UnmanagedType.U4)]

                public UInt32 dwPixelArrayFormat;

                [MarshalAs(UnmanagedType.I4)]

                public Int32 lWidth;

                [MarshalAs(UnmanagedType.I4)]

                public Int32 lHeight;

                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]

                public Int32[] lPitch; 

                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]

                public IntPtr[] pPlane;   //对于结构体中的指针数组,一般采用IntPtr数组

            }

    对于上面的这个结构体,如果在C/C++中出现了结构体指针,那么我们应该在C#中使用IntPtr类型变量,然后使用如下方法将指针指向结构体。

    定义结构体对象S,则在C#中获取结构体指针的方法如下:

    IntPtr intptr = Marshal.AllocHGlobal(Marshal.SizeOf(S));
    Marshal.StructureToPtr(S, intptr, false); //将指针intptr指向结构体

    操作之后一定要释放内存——
    Marshal.FreeHGlobal(intptr);//释放分配的非托管内存。

    反之也可以由指向结构体的指针变量获取结构体。Marshal.PtrToStructure();

  • 相关阅读:
    有一天,我们能这样相爱吗?
    端午节来源六说
    一个ini类代替缓存使用
    创意生活可爱香皂
    漂亮的韩国发饰
    Oracle中PL/SQL单行函数和组函数详解
    真正爱你的女人是这样的
    执子之手,与子偕老。你同意么?
    男人如茶
    Oracle SQL 內置函數大全
  • 原文地址:https://www.cnblogs.com/shenchao/p/2970092.html
Copyright © 2011-2022 走看看