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