zoukankan      html  css  js  c++  java
  • .net 互操作之p/invoke 数据封送之字符串(2)

         

    使用Unicode传递

    一.定义托管函数

    // void __cdecl TestStringArgumentsInOut(const wchar_t* inString, wchar_t* outString, int bufferSize);
     [DllImport(_dllName, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
     private extern static void TestStringArgumentsFixLength(string inString, StringBuilder outString, int bufferSize);


    第一个参数是传入的参数,第二个是输出的.

    注意
    1.String是不可变类型,const wchar_t* inString
    2.wchar_t*为Unicode,所以指定为CharSet = CharSet.Unicode,设置为Unicode则整个函数的参数均为以Unicode传递
    3.第二个参数是输出参数,所以设置为StringBuilder类型

    下面示例功能为拷贝字符串,托管代码分配内存

    二.非托管代码示例

    void __cdecl TestStringArgumentsFixLength(
         const wchar_t* inString, wchar_t* outString, int bufferSize)
     {
         if(NULL != inString)
         {
             wcscpy_s(outString, bufferSize, inString);
         }
     }

    三.托管代码

    private static void TestStringArgumentsFixLength()
            {
                string inString = "This is a input string.";
     
                int bufferSize = inString.Length;
                StringBuilder sb = new StringBuilder(bufferSize);
     
               TestStringArgumentsFixLength(inString, sb, bufferSize + 1);
     
               Console.WriteLine("Original: {0}", inString);
                Console.WriteLine("Copied: {0}", sb.ToString());
            }

    以MarshalAs的方式传递

    MarshalAs标签定义的话,可以细化函数参数是否以Unicode形式传递,可能非托管函数既有ANSI字符串也有Unicode字符串。
    MarshalAs以指定UnmanagedType参数来设置要传递参数的类型,UnmanagedType定义了很多非托管类型

    1.定义托管函数

    // void __cdecl TestStringMarshalArguments(const char* inAnsiString, const wchar_t* inUnicodeString, wchar_t* outUnicodeString, int outBufferSize)
     [DllImport(_dllName, CallingConvention = CallingConvention.Cdecl)]
     private extern static void TestStringMarshalArguments(
         [MarshalAs(UnmanagedType.LPStr)] string inAnsiString, 
         [MarshalAs(UnmanagedType.LPWStr)] string inUnicodeString,
         [MarshalAs(UnmanagedType.LPWStr)] StringBuilder outStringBuffer,
         int outBufferSize);

    第一个是ANSI字符串,第二传入的Unicode字符串和第三个是传出的Unicode字符串

    2.定义非托管代码

    void __cdecl TestStringMarshalArguments(const char* inAnsiString, const wchar_t* inUnicodeString, 
                                             wchar_t* outUnicodeString, int outBufferSize)
     {
         
         size_t ansiStrLength = strlen(inAnsiString);
         size_t uniStrLength = wcslen(inUnicodeString);
     
         size_t totalSize = ansiStrLength + uniStrLength + 2;
         wchar_t* tempBuffer = new(std::nothrow) wchar_t[totalSize];
         if(NULL == tempBuffer)
         {
             return;
         }
     
         wmemset(tempBuffer, 0, totalSize);
         mbstowcs(tempBuffer, inAnsiString, totalSize);
         wcscat_s(tempBuffer, totalSize, L" ");
         wcscat_s(tempBuffer, totalSize, inUnicodeString);
         wcscpy_s(outUnicodeString, outBufferSize, tempBuffer);
         delete[] tempBuffer;
     }


    3.托管代码测试

    private static void TestMarshalArguments()
     {
         string string1 = "Hello";
         string string2 = "世界!?";
         int outBufferSize = string1.Length + string2.Length + 2;
         StringBuilder outBuffer = new StringBuilder(outBufferSize);
         TestStringMarshalArguments(string1, string2, outBuffer, outBufferSize);
     
         Console.WriteLine("{0}", outBuffer.ToString());
     }


    输出结果:
    image_2

    释放由非托管函数分配的内存

    当在函数中传递引用参数时,非托管函数则需要分配内存

    一.自动释放

    1.非托管函数

    void __cdecl TestStringArgumentOut(int id, wchar_t** ppString)
     {
         if(NULL != ppString)
         {
             int bufferSize = 128;
             *ppString = (wchar_t*)CoTaskMemAlloc(bufferSize);
             swprintf_s(*ppString, bufferSize/sizeof(wchar_t), L"Out string of ID: %d", id);
         }
     }


    使用CoTaskMemAlloc方法来申请内存,则会自动调用CoTaskMemFree来释放非托管内存,这就意味了托管代码无需处理内存问题,减轻了托管代码的的复杂度.

    2.定义托管函数

    [DllImport(_dllName, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
     private extern static void TestStringArgumentOut(int id, ref string outString);


    需要以ref 关键字来制定字符串是输出的,以表示此参数是引用类型

    3.测试

    string strResult = "";
     TestStringArgumentOut(2, ref strResult);
     Console.WriteLine("Return string value: {0}", strResult);

    输出
    image_4

    二.手动控制

    非托管代码不变,重新定义托管函数,以IntPtr 类型代替String类型

    // NATIVELIB_API void __cdecl TestStringArgumentOut(int id, wchar_t** ppString);
     [DllImport(_dllName, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl, EntryPoint = "TestStringArgumentOut")]
     private extern static void TestStringArgumentOutIntPtr(int id, ref IntPtr outString);


    测试代码

    string strResult;
     IntPtr strIntPtr = IntPtr.Zero;
     TestStringArgumentOutIntPtr(1, ref strIntPtr);
    //数据类型转换,复制数据

    strResult = Marshal.PtrToStringUni(strIntPtr); //手动释放内存
    Marshal.FreeCoTaskMem(strIntPtr); Console.WriteLine("Return string IntPtr: {0}", strResult);

    封送作为返回值的字符串

    看以下托管函数定义,同上返回IntPtr 则需要手动释放内存,直接返回String的则会自动处理

    // void wchar_t* __cdecl TestStringAsResult()
     [DllImport(_dllName, CharSet = CharSet.Unicode, 
         CallingConvention = CallingConvention.Cdecl, 
         EntryPoint = "TestStringAsResult")]
     private extern static IntPtr TestStringAsResultIntPtr(int id);
     
     [DllImport(_dllName, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
     private extern static string TestStringAsResult(int id);

    测试代码

    // 1. IntPtr
     string result;
     IntPtr strPtr = TestStringAsResultIntPtr(1);
     result = Marshal.PtrToStringUni(strPtr);
     // Marshal.FreeCoTaskMem(strPtr);
     Console.WriteLine("Return string IntPtr: {0}", result);
     
     // 2. String
     result = TestStringAsResult(2);
     Console.WriteLine("Return string value: {0}", result);

    特殊的BSTR

    必须采用手动释放,不可以自动释放

  • 相关阅读:
    《一个人的村庄》 ——刘亮程
    uva 11020
    Codeforces Round #190 (Div. 2) B. Ciel and Flowers
    hdu3308 线段树——区间合并
    线段树,区间更新
    vim 被墙
    ubuntu12.04 修复Grub2
    windows下mysql数据库忘记密码
    高性能的异步爬虫
    中间件
  • 原文地址:https://www.cnblogs.com/Clingingboy/p/1809619.html
Copyright © 2011-2022 走看看