zoukankan      html  css  js  c++  java
  • c# 调用 C++ dll 传入传出 字符串

    c# 调用 C++ dll 传入传出 字符串

    分类:
    windows

    C#调用 非托管C++ dll 传入Stringbuilder、ref string 、 ref char 等都报错,如mscorlib.dll 异常、其他信息: 尝试读取或写入受保护的内存。这通常指示其他内存已损坏 等等,后来发现是dll 生成后一直没更新,放错位置了。。。 = =||

    不过也学习了一下编译器及类型相关的知识,整理如下:

     

    1、 cl.exe /Gz 参数指定编译为 __stdcall 调用方式,默认为 __cdecl

    2、C#中的char是两个字节

    http://msdn.microsoft.com/zh-cn/library/x9h8tsay(v=vs.80).aspx

     

    类型范围大小.NET Framework 类型

    char

    U+0000 到 U+ffff

    16 位 Unicode 字符

    System.Char


     

    类型

    范围

    大小

    .NET Framework 类型

    byte

    0 到 255

    无符号 8 位整数

    System.Byte

     

    3、C++ dll 类型与 C#类型对应关系

    参考:

    本以为这篇搜集整理的代码会是很不错的文章,花了一天时间,搜索到最后居然出来一篇叫做"C# 与 C++ 数据类型对照表"的文章.几乎囊括掉和大部分的数据了,太打击我了. 本文中有部分的数据没有测试.也有一些不错的是看了上百篇网文对比整理得来的.希望有帮助.

            //C++中的DLL函数原型为
            //extern "C" __declspec(dllexport) bool 方法名一(const char* 变量名1, unsigned char* 变量名2)
            //extern "C" __declspec(dllexport) bool 方法名二(const unsigned char* 变量名1, char* 变量名2)

            //C#调用C++的DLL搜集整理的所有数据类型转换方式,可能会有重复或者多种方案,自己多测试
            //c++:HANDLE(void   *)          ----    c#:System.IntPtr 
            //c++:Byte(unsigned   char)     ----    c#:System.Byte 
            //c++:SHORT(short)              ----    c#:System.Int16 
            //c++:WORD(unsigned   short)    ----    c#:System.UInt16 
            //c++:INT(int)                  ----    c#:System.Int16
            //c++:INT(int)                  ----    c#:System.Int32 
            //c++:UINT(unsigned   int)      ----    c#:System.UInt16
            //c++:UINT(unsigned   int)      ----    c#:System.UInt32
            //c++:LONG(long)                ----    c#:System.Int32 
            //c++:ULONG(unsigned   long)    ----    c#:System.UInt32 
            //c++:DWORD(unsigned   long)    ----    c#:System.UInt32 
            //c++:DECIMAL                   ----    c#:System.Decimal 
            //c++:BOOL(long)                ----    c#:System.Boolean 
            //c++:CHAR(char)                ----    c#:System.Char 
            //c++:LPSTR(char   *)           ----    c#:System.String 
            //c++:LPWSTR(wchar_t   *)       ----    c#:System.String 
            //c++:LPCSTR(const   char   *)  ----    c#:System.String 
            //c++:LPCWSTR(const   wchar_t   *)      ----    c#:System.String 
            //c++:PCAHR(char   *)   ----    c#:System.String 
            //c++:BSTR              ----    c#:System.String 
            //c++:FLOAT(float)      ----    c#:System.Single 
            //c++:DOUBLE(double)    ----    c#:System.Double 
            //c++:VARIANT           ----    c#:System.Object 
            //c++:PBYTE(byte   *)   ----    c#:System.Byte[]

            //c++:BSTR      ----    c#:StringBuilder
            //c++:LPCTSTR   ----    c#:StringBuilder
            //c++:LPCTSTR   ----    c#:string
            //c++:LPTSTR    ----    c#:[MarshalAs(UnmanagedType.LPTStr)] string 
            //c++:LPTSTR 输出变量名    ----    c#:StringBuilder 输出变量名
            //c++:LPCWSTR   ----    c#:IntPtr
            //c++:BOOL      ----    c#:bool   
            //c++:HMODULE   ----    c#:IntPtr    
            //c++:HINSTANCE ----    c#:IntPtr 
            //c++:结构体    ----    c#:public struct 结构体{}; 
            //c++:结构体 **变量名   ----    c#:out 变量名   //C#中提前申明一个结构体实例化后的变量名
            //c++:结构体 &变量名    ----    c#:ref 结构体 变量名
            

            //c++:WORD      ----    c#:ushort
            //c++:DWORD     ----    c#:uint
            //c++:DWORD     ----    c#:int

            //c++:UCHAR     ----    c#:int
            //c++:UCHAR     ----    c#:byte
            //c++:UCHAR*    ----    c#:string
            //c++:UCHAR*    ----    c#:IntPtr

            //c++:GUID      ----    c#:Guid
            //c++:Handle    ----    c#:IntPtr
            //c++:HWND      ----    c#:IntPtr
            //c++:DWORD     ----    c#:int
            //c++:COLORREF  ----    c#:uint


            //c++:unsigned char     ----    c#:byte
            //c++:unsigned char *   ----    c#:ref byte
            //c++:unsigned char *   ----    c#:[MarshalAs(UnmanagedType.LPArray)] byte[]
            //c++:unsigned char *   ----    c#:[MarshalAs(UnmanagedType.LPArray)] Intptr

            //c++:unsigned char &   ----    c#:ref byte
            //c++:unsigned char 变量名      ----    c#:byte 变量名
            //c++:unsigned short 变量名     ----    c#:ushort 变量名
            //c++:unsigned int 变量名       ----    c#:uint 变量名
            //c++:unsigned long 变量名      ----    c#:ulong 变量名

            //c++:char 变量名       ----    c#:byte 变量名   //C++中一个字符用一个字节表示,C#中一个字符用两个字节表示
            //c++:char 数组名[数组大小]     ----    c#:MarshalAs(UnmanagedType.ByValTStr, SizeConst = 数组大小)]        public string 数组名; ushort

            //c++:char *            ----    c#:string       //传入参数
            //c++:char *            ----    c#:StringBuilder//传出参数
            //c++:char *变量名      ----    c#:ref string 变量名
            //c++:char *输入变量名  ----    c#:string 输入变量名
            //c++:char *输出变量名  ----    c#:[MarshalAs(UnmanagedType.LPStr)] StringBuilder 输出变量名

            //c++:char **           ----    c#:string
            //c++:char **变量名     ----    c#:ref string 变量名
            //c++:const char *      ----    c#:string
            //c++:char[]            ----    c#:string
            //c++:char 变量名[数组大小]     ----    c#:[MarshalAs(UnmanagedType.ByValTStr,SizeConst=数组大小)] public string 变量名;

            //c++:struct 结构体名 *变量名   ----    c#:ref 结构体名 变量名
            //c++:委托 变量名   ----    c#:委托 变量名

            //c++:int       ----    c#:int
            //c++:int       ----    c#:ref int
            //c++:int &     ----    c#:ref int
            //c++:int *     ----    c#:ref int      //C#中调用前需定义int 变量名 = 0;

            //c++:*int      ----    c#:IntPtr
            //c++:int32 PIPTR *     ----    c#:int32[]
            //c++:float PIPTR *     ----    c#:float[]
           

            //c++:double** 数组名          ----    c#:ref double 数组名
            //c++:double*[] 数组名          ----    c#:ref double 数组名
            //c++:long          ----    c#:int
            //c++:ulong         ----    c#:int
            
            //c++:UINT8 *       ----    c#:ref byte       //C#中调用前需定义byte 变量名 = new byte();       


            //c++:handle    ----    c#:IntPtr
            //c++:hwnd      ----    c#:IntPtr
            
            
            //c++:void *    ----    c#:IntPtr        
            //c++:void * user_obj_param    ----    c#:IntPtr user_obj_param
            //c++:void * 对象名称    ----    c#:([MarshalAs(UnmanagedType.AsAny)]Object 对象名称


            
            //c++:char, INT8, SBYTE, CHAR                               ----    c#:System.SByte  
            //c++:short, short int, INT16, SHORT                        ----    c#:System.Int16  
            //c++:int, long, long int, INT32, LONG32, BOOL , INT        ----    c#:System.Int32  
            //c++:__int64, INT64, LONGLONG                              ----    c#:System.Int64  
            //c++:unsigned char, UINT8, UCHAR , BYTE                    ----    c#:System.Byte  
            //c++:unsigned short, UINT16, USHORT, WORD, ATOM, WCHAR , __wchar_t             ----    c#:System.UInt16  
            //c++:unsigned, unsigned int, UINT32, ULONG32, DWORD32, ULONG, DWORD, UINT      ----    c#:System.UInt32  
            //c++:unsigned __int64, UINT64, DWORDLONG, ULONGLONG                            ----    c#:System.UInt64  
            //c++:float, FLOAT                                                              ----    c#:System.Single  
            //c++:double, long double, DOUBLE                                               ----    c#:System.Double 

            //Win32 Types        ----  CLR Type  
           

            //Struct需要在C#里重新定义一个Struct
            //CallBack回调函数需要封装在一个委托里,delegate static extern int FunCallBack(string str);

            //unsigned char** ppImage替换成IntPtr ppImage
            //int& nWidth替换成ref int nWidth
            //int*, int&, 则都可用 ref int 对应
            //双针指类型参数,可以用 ref IntPtr
            //函数指针使用c++: typedef double (*fun_type1)(double); 对应 c#:public delegate double  fun_type1(double);
            //char* 的操作c++: char*; 对应 c#:StringBuilder;
            //c#中使用指针:在需要使用指针的地方 加 unsafe


            //unsigned   char对应public   byte
            /*
             * typedef void (*CALLBACKFUN1W)(wchar_t*, void* pArg);
             * typedef void (*CALLBACKFUN1A)(char*, void* pArg);
             * bool BIOPRINT_SENSOR_API dllFun1(CALLBACKFUN1 pCallbackFun1, void* pArg);
             * 调用方式为
             * [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
             * public delegate void CallbackFunc1([MarshalAs(UnmanagedType.LPWStr)] StringBuilder strName, IntPtr pArg);
             * 
             * 
             */

     

    4、C#调用C++dll的几种传参方式

    refer: http://www.camnpr.com/archives/293.html

    C#调用非托管DLL中的API:
     
    LONG APIENTRY devwdm_GetImageBuffer(BYTE *pImageMem);
      函数功能: 采集一帧RGB24图像到内存
      pImageMem: 图像缓冲区指针

    C#调用:
     

    C# code
    [DllImport("devwdm.dll")] public static extern int devwdm_GetImageBuffer(IntPtr pImageMem);


    于是报错:尝试读取或写入受保护的内存。这通常指示其他内存已损坏。
    求助于大家,根据大家的意见,把API中的 BYTE* 转换到C#中,分别用 byte[] 、IntPtr 、ref byte[]、 ...甚至用unsafe了,可是还是报错,有人说内存不够大,于是我非配了很大的内存,扔报错...

    万般无奈,去C++的示例程序中看,示例程序中调用该函数没有任何问题。

    pImageMem是用来存放图象数据的缓冲区 字节数组(长*宽*3)
    lpsz是文件名(用于保存图象) 字符数组(Unicode/ANSI)
    devwdm_GetImageBuffer(pImageMem); 对字节数组赋值
    CT_SaveBmp(lpsz,pImageMem,m_strWideth,m_strHeight,0);以BMP格式保存
    CT_SaveJpeg(lpsz,pImageMem,m_strWideth,m_strHeight,0);以JPG格式保存

    以C#重写上述功能,要注意的几点:
    1,获取正确的m_strWideth和m_strHeight ,据此申请内存块:
      IntPtr ptrImage = Marshal.AllocHGlobal(m_strWideth*m_strHeight*3);
    2,构建文件名,szFile是用户输入的字符串?
      string filename = "XXX";
      IntPtr ptrFileName = Marshal.AllocHGlobal(filename.Length+1);
      Marshal.Copy(s.ToCharArray(), 0, ptrFileName, s.Length);
    3,获取图像数据:
      devwdm_GetImageBuffer(ptrImage);
    4,保存BMP
      CT_SaveBmp(ptrFileName,ptrImage,m_strWideth,m_strHeight,0);

    托管数组向非托管代码封送:

    试试这样:
    如果有byte[] data字节数组,如下调用:
    devwdm_GetImageBuffer([In, MarshalAs( UnmanagedType.LPArray)] data);


    或者手工转换成非托管数组:
    IntPtr ptr = Marshal.AllocHGlobal(data.Length);//申请非托管内存块(与data大小一样)
    Marshal.Copy(data,0,ptr,data.Length);//将托管数据复制到非托管数据
    devwdm_GetImageBuffer(ptr);//直接以非托管内存块地址为参数
    Marshal.FreeHGlobal(ptr);//处理完后记得释放内存

    发生错误的原因是devwdm_GetImageBuffer的参数的指针没有正确指到数据内存块,当指向受保护的系统内存块并且发生读写时,就会提示上述错误,与内存大小一点关系没有

     

    byte[] UUID2 = new byte[37];
    UUID2 = System.Text.Encoding.ASCII.GetBytes(Request["uid"].Trim());

    char& 和 int&  ,&是取地址,在c#中byte型的数组就是表示地址的,所以,对应的类型就是byte,如果是指定长度的char的话,要用byte[]  ,一定要指定长度,只可大不可小。具体咨询本站站长。

  • 相关阅读:
    Codeforces Round #592 (Div. 2)C. The Football Season(暴力,循环节)
    Educational Codeforces Round 72 (Rated for Div. 2)D. Coloring Edges(想法)
    扩展KMP
    poj 1699 Best Sequence(dfs)
    KMP(思路分析)
    poj 1950 Dessert(dfs)
    poj 3278 Catch That Cow(BFS)
    素数环(回溯)
    sort与qsort
    poj 1952 buy low buy lower(DP)
  • 原文地址:https://www.cnblogs.com/gosteps/p/5241867.html
Copyright © 2011-2022 走看看