C# 調用 C++ dll 函數 時傳遞字符串 需要注意的問題(zz)


最近接手一個項目,主要是vc6的dll 給c#調用,就是為了用現成的dll,免得重新用c#開發

主要涉及參數傳遞和內存釋放的問題。

 

vc6部分==================

 

頭文件部分

#ifdef __cplusplus

extern "C" {

#endif

__declspec(dllexport) char* getStringValue();

 

#ifdef __cplusplus

}

#endif

 

源文件部分

char* getStringValue()

{

....

    //有人說要 static char *strdata = new char[size];

    char *strdata = new char[size];

    strncpy(strdata,"若干字符",size);

    stardata[size-1] = '\0';

    return strdata;

}

 

 c#部分,一直不順利 用了 string 也用了 StringBuilder

以下是錯誤的

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            StringBuilder data = test.getNavigaTreeListValue();

            Console.WriteLine("result: " + data);

            Console.ReadLine();

            test.deleteGlobalDataPoint(data);
        }
    }


    class test
    {

        [DllImport("utwebcommlib.dll")]
        public static extern StringBuilder getNavigaTreeListValue( );


        [DllImport("utwebcommlib.dll")]
        public static extern bool deleteGlobalDataPoint( StringBuilder buffer);

    }

}

 

在運行時候總是遇到 讀取內存越界類似的錯誤 總以為getStringValue函數返回new的指針是不是有什么問題

但是這個東西在vs2008下是好的。到了vs2010就報異常。最后百度,在最后附上了解決方法的連接。

以下的才是正確的

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            IntPtr intPtr = test.getNavigaTreeListValue();

            string data = Marshal.PtrToStringAnsi(intPtr);

            Console.WriteLine("result: " + data);

            Console.ReadLine();

            test.deleteGlobalDataPoint(intPtr );
        }
    }


    class test
    {

        [DllImport("utwebcommlib.dll")]
        public static extern IntPtr getNavigaTreeListValue();


        [DllImport("utwebcommlib.dll")]
        public static extern bool deleteGlobalDataPoint(IntPtr buffer);

        [DllImport("utwebcommlib.dll")]
        public static extern int AddValue();

    }

}

 

 

非常感謝 。http://blog.csdn.net/shilogic/article/details/7027360 

1:C# 調用 返回 字符串 C++ native dll 函數 的注意事項:

a:C++ DLL的返回值,安全的做法是分配一個全局 char 數組,把要返回的 char * 復制到這個 char 數組中,

 

char   buff[255];    

const char* __stdcall ReturnString()
{
  strcpy(buff,"xxxxxxxxxxxxxxx");
  return buff;
 }

b:C# 收到 字符串后,需要 Marshal

[DllImport("VC.dll", EntryPoint = "ReturnString", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Winapi)]
public static extern IntPtr ReturnString();

//調用VCDLL的代碼...

IntPtr intPtr = ReturnString();

string str = Marshal.PtrToStringAnsi(intPtr);

...

因為 C++ 返回的是 char* ,是個指針,所以c# 要用 IntPtr 來接回。

Marshal.PtrToStringAnsi MSDN上的解釋:將非托管 ANSI 字符串中第一個空值(空值就是\0)之前的所有字符復制到托管 String。將每個 ANSI 字符擴展為 Unicode 字符。

 

2:用參數傳遞,即C++dll 函數的參數 定義為 char*,而C#傳遞 StringBuilder 給 c++

a:c# 創建一個 StringBuilder,並初始化 capacity后傳給C++

[DllImport("VC.dll", EntryPoint = "ProcessString", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Winapi)]
public static extern void ProcessString(StringBuilder str);

//調用VCDLL的代碼...

StringBuilder str = new StringBuilder(255); //255 是 capacity

ProcessString(str);

MessageBox.Show(str); //不需要Marshal,直接使用

...

 

b:C++ DLL函數

const char* __stdcall ProcessString(char* str)
{

  //str 是 c# 創建的 StringBuilder,長度是255
  strcpy(str,"xxxxxxxxxxxxxxx");
  return buff;
}

其他的請參考msdn中的c++與c#的類型轉換 對應關系如下:

 C++ ---- C#

傳入的char*  ----string

傳出的char* ---- StringBuilder(預分配空間)

short  ----short

char ---- byte

char[n] ---- fixed byte[n]

結構指針  ----結構指針

函數指針 ---- 委托

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM