日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

C#调用C++Dll封装时遇到的一系列问题 参考

發布時間:2023/12/18 C# 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C#调用C++Dll封装时遇到的一系列问题 参考 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.






    在合作開發時,C#時常需要調用C++DLL,當傳遞參數時時常遇到問題,尤其是傳遞和返回字符串是,現總結一下,分享給大家:

    VC++中主要字符串類型為:LPSTR,LPCSTR, LPCTSTR, string, CString, LPCWSTR, LPWSTR等
    但轉為C#類型卻不完全相同。

    主要有如下幾種轉換:


    將string轉為IntPtr:IntPtr System.Runtime.InteropServices.Marshal.StringToCoTaskMemAuto(string)

    將IntPtr轉為string:string System.Runtime.InteropServices.MarshalPtrToStringAuto(IntPtr)

    ?

    類型對照:

    BSTR ---------? StringBuilder

    LPCTSTR --------- StringBuilder

    LPCWSTR ---------? IntPtr

    handle---------IntPtr

    hwnd-----------IntPtr

    char *----------string

    int * -----------ref int

    int &-----------ref int

    void *----------IntPtr

    unsigned char *-----ref byte

    Struct需要在C#里重新定義一個Struct

    CallBack回調函數需要封裝在一個委托里,delegate static extern int FunCallBack(string str);

    注意在每個函數的前面加上public static extern +返回的數據類型,如果不加public ,函數默認為私有函數,調用就會出錯。


    在C#調用C++ DLL封裝庫時會出現兩個問題:


    1. 數據類型轉換問題?
    2. 指針或地址參數傳送問題

    ??? 首先是數據類型轉換問題。因為C#是.NET語言,利用的是.NET的基本數據類型,所以實際上是將C++的數據類型與.NET的基本數據類型進行對應。

    ??? 例如C++的原有函數是:

    int __stdcall FunctionName(unsigned char param1, unsigned short param2)

    ??? 其中的參數數據類型在C#中,必須轉為對應的數據類型。如:

    [DllImport(“ COM DLL path/file ”)]?
    extern static int FunctionName(byte param1, ushort param2)

    ??? 因為調用的是__stdcall函數,所以使用了P/Invoke的調用方法。其中的方法FunctionName必須聲明為靜態外部函數,即加上extern static聲明頭。我們可以看到,在調用的過程中,unsigned char變為了byte,unsigned short變為了ushort。變換后,參數的數據類型不變,只是聲明方式必須改為.NET語言的規范。

    ??? 我們可以通過下表來進行這種轉換:

    Win32 Types?
    CLR Type

    char, INT8, SBYTE, CHAR?
    System.SByte

    short, short int, INT16, SHORT?
    System.Int16

    int, long, long int, INT32, LONG32, BOOL , INT?
    System.Int32

    __int64, INT64, LONGLONG?
    System.Int64

    unsigned char, UINT8, UCHAR , BYTE?
    System.Byte

    unsigned short, UINT16, USHORT, WORD, ATOM, WCHAR , __wchar_t?
    System.UInt16

    unsigned, unsigned int, UINT32, ULONG32, DWORD32, ULONG, DWORD, UINT?
    System.UInt32

    unsigned __int64, UINT64, DWORDLONG, ULONGLONG?
    System.UInt64

    float, FLOAT?
    System.Single

    double, long double, DOUBLE?
    System.Double


    ??? 之后再將CLR的數據類型表示方式轉換為C#的表示方式。這樣一來,函數的參數類型問題就可以解決了。

    ??? 現在,我們再來考慮下一個問題,如果要調用的函數參數是指針或是地址變量,怎么辦?

    ??? 對于這種情況可以使用C#提供的非安全代碼來進行解決,但是,畢竟是非托管代碼,垃圾資源處理不好的話對應用程序是很不利的。所以還是使用C#提供的ref以及out修飾字比較好。

    ??? 同上面一樣,我們也舉一個例子:

    int __stdcall FunctionName(unsigned char &param1, unsigned char *param2)

    ??? 在C#中對其進行調用的方法是:

    [DllImport(“ file ”)]?
    extern static int FunctionName(ref byte param1, ref byte param2)

    ??? 看到這,可能有人會問,&是取地址,*是傳送指針,為何都只用ref就可以了呢?一種可能的解釋是ref是一個具有重載特性的修飾符,會自動識別是取地址還是傳送指針。

    ??? 在實際的情況中,我們利用參數傳遞地址更多還是用在傳送數組首地址上。?
    如:byte[] param1 = new param1(6);

    ??? 在這里我們聲明了一個數組,現在要將其的首地址傳送過去,只要將param1數組的第一個元素用ref修飾。具體如下:

    [DllImport(“ file ”)]?
    extern static int FunctionName(ref byte param1[1], ref byte param2)?
    ??
    文章出處:DIY部落(http://www.diybl.com/course/3_program/c++/cppjs/200886/134816.html)

    ?

    ?

    C# 中調用DLL

    ?

    為了能用上原來的C++代碼,只好研究下從C# 中調用DLL
    首先必須要有一個聲明,使用的是DllImport關鍵字:?
    包含DllImport所在的名字空間?
    using System.Runtime.InteropServices;?
    public class XXXX{

    [DllImport(“MyDLL.dll")]?
    public static extern int mySum (int a,int b);
    ?
    }


    [DllImport(“MyDLL.dll")]?
    public static extern int mySum (int a,int b);?
    代碼中DllImport關鍵字作用是告訴編譯器入口點在哪里,并將打包函數捆綁在這個類中?
    在調用的時候?
    在類中的時候 直接 ? mySum(a,b);就可以了?
    在其他類中調用: XXXX. mySum(a,b);?
    ?
    [DllImport(“MyDLL.dll”)]在申明的時候還可以添加幾個屬性?
    [DllImport(“MyDLL.dll", EntryPoint=" mySum ",CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)?
    ]?
    EntryPoint: 指定要調用的 DLL 入口點。默認入口點名稱是托管方法的名稱 。?
    CharSet: 控制名稱重整和封送 String 參數的方式 (默認是UNICODE)?
    CallingConvention指示入口點的函數調用約定(默認WINAPI)(上次報告講過的)?
    SetLastError 指示被調用方在從屬性化方法返回之前是否調用 SetLastError Win32 API 函數 (C#中默認false )


    int 類型?
    [DllImport(“MyDLL.dll")]?
    //返回個int 類型?
    public static extern int mySum (int a1,int b1);?
    //DLL中申明?
    extern “C” __declspec(dllexport)? int WINAPI mySum(int a2,int b2)?
    {?
    //a2 b2不能改變a1 b1
    //a2=..
    //b2=...
    ?return a+b;?
    }

    //參數傳遞int 類型?
    public static extern int mySum (ref int a1,ref int b1);?
    //DLL中申明?
    extern “C” __declspec(dllexport)? int WINAPI mySum(int *a2,int *b2)?
    {?
    //可以改變 a1, b1
    *a2=...
    *b2=...
    ?return a+b;?
    }?


    DLL 需傳入char *類型?
    [DllImport(“MyDLL.dll")]?
    //傳入值?
    public static extern int mySum (string? astr1,string bstr1);?
    //DLL中申明?
    extern “C” __declspec(dllexport)? int WINAPI mySum(char * astr2,char * bstr2)?
    {?
    //改變astr2 bstr 2? ,astr1 bstr1不會被改變
    ?return a+b;?
    }


    DLL 需傳出char *類型?
    [DllImport(“MyDLL.dll")]?
    // 傳出值
    public static extern int mySum (StringBuilder abuf, StringBuilder bbuf );?
    //DLL中申明?
    extern “C” __declspec(dllexport)? int WINAPI mySum(char * astr,char * bstr)?
    {?
    //傳出char * 改變astr bstr -->abuf, bbuf可以被改變
    ?return a+b;?
    }?
    ?
    DLL 回調函數?

    BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam)?



    using System;?
    using System.Runtime.InteropServices;?
    public delegate bool CallBack(int hwnd, int lParam); //定義委托函數類型?
    public class EnumReportApp?
    {?
    [DllImport("user32")]?
    public static extern int EnumWindows(CallBack x, int y);?
    public static void Main() {?
    CallBack myCallBack = new CallBack(EnumReportApp.Report); EnumWindows(myCallBack, 0);?
    }?
    public static bool Report(int hwnd, int lParam)?
    {?
    Console.Write("Window handle is ");?
    Console.WriteLine(hwnd); return true;?
    }?
    }?
    ?

    DLL? 傳遞結構??
    BOOL PtInRect(const RECT *lprc, POINT pt);?

    using System.Runtime.InteropServices;?
    [StructLayout(LayoutKind.Sequential)]?
    public struct Point {
    ?public int x;?
    public int y;
    ?}?
    [StructLayout(LayoutKind.Explicit)]?
    ?public struct Rect?
    ?{?
    [FieldOffset(0)] public int left;?
    [FieldOffset(4)] public int top;
    [FieldOffset(8)] public int right;?
    [FieldOffset(12)] public int bottom;
    ?}?
    Class XXXX {?
    ?[DllImport("User32.dll")]?
    public static extern bool PtInRect(ref? Rect r, Point p);?
    ?}

    DLL 回調函數,傳遞結構 想看的msdn里面都有專題介紹,看的我都是暈暈的:)

    其他參考請搜索:

    在C#程序設計中使用Win32類庫
    C#中調用C++托管Dll
    如何在C#中加載自己編寫的動態鏈接庫

    相關文章:Creating a P/Invoke Library


    能用上DLL以后感覺還是很好的,原來的C++代碼只要修改編譯通過就可以了,
    高興沒多久,發現.net2005居然可以用VB,VC開發智能設備項目,可以創建MFC智能設備項目
    暈暈,難道可以直接用MFC來開發smartphone的程序了,趕緊看看,,,

    總結

    以上是生活随笔為你收集整理的C#调用C++Dll封装时遇到的一系列问题 参考的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。