none
【求助】.NET 2.0 升级到 .NET 4.5.1 出现问题 RRS feed

  • 问题

  • 使用C++编写非托管DLL,代码如下

    extern "C" _declspec(dllexport) LPCTSTR Func4()

    {

    return L"456789--123456789";

    }

    使用C#调用,代码如下

    class aaa
    {
        [DllImport(@"MFCLibrary1.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
        public static extern string Func4();
    }
    
    class Program
    {
        private static void Main(string[] args)
        {
            string zz = aaa.Func4();
            Console.WriteLine(zz);
    
            Console.ReadLine();
        }
    }

    在.NET2.0 3.0 3.5下,编译,这种LPCTSTR直接返回给string的方式,都是好用的

    在.NET4.0 4.5 4.5.1下,编译,这种LPCTSTR直接返回给string的方式,就会异常退出

    请问这是为什么?

    需要设置什么东西吗?

    还是需要改变方式?

    谢谢了


    2014年3月20日 2:23

答案

  • 转换一下思路即可,既然DLLImport定义时,IntPtr是安全的,然而你又想把InPtr直接赋值给String,那可以用一个中间类来做隐式转换,如下所示:
    class aaa
    {
        [DllImport(@"MFCLibrary1.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
        public static extern MyIntPtr Func4();
    }
    
    class Program
    {
        private static void Main(string[] args)
        {
            string zz = aaa.Func4();
            Console.WriteLine(zz);
    
            Console.ReadLine();
        }
    }
    
    public struct MyIntPtr
    {
        public IntPtr Pointer;
    
        public static implicit operator string(MyIntPtr ptr)
        {
            return Marshal.PtrToStringAnsi(ptr.Pointer);
        } 
    }

    2014年3月20日 9:12

全部回复

  • Hi,比较安全的做法是使用Marshal.PtrToStringXXX函数来获取字符串,比如,可以试一下Marshal.PtrToStringAnsi:

    class aaa
    {
        [DllImport(@"MFCLibrary1.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr Func4();
    }
    
    class Program
    {
        private static void Main(string[] args)
        {
            string zz = Marshal.PtrToStringAnsi(aaa.Func4());
            Console.WriteLine(zz);
    
            Console.ReadLine();
        }
    }

    2014年3月20日 8:10
  • 你的那个 C++ DLL 是同一个,还是分别编译的两个?

    2014年3月20日 8:18
  • 你的那个 C++ DLL 是同一个,还是分别编译的两个?

    上面的代码是C++的,编译成MFCLibrary1.dll

    下面的代码是C#的,调用上面的MFCLibrary1.dll中的Func4函数


    2014年3月20日 8:46
  • Hi,比较安全的做法是使用Marshal.PtrToStringXXX函数来获取字符串,比如,可以试一下Marshal.PtrToStringAnsi:

    class aaa
    {
        [DllImport(@"MFCLibrary1.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr Func4();
    }
    
    class Program
    {
        private static void Main(string[] args)
        {
            string zz = Marshal.PtrToStringAnsi(aaa.Func4());
            Console.WriteLine(zz);
    
            Console.ReadLine();
        }
    }

    这个方法试验了一下

    确实好用

    不过还是想知道

    该怎么才能直接使用public static extern string Func4();

    如果是改成IntPtr的话

    需要改动的地方太多了

    2014年3月20日 8:48
  • 转换一下思路即可,既然DLLImport定义时,IntPtr是安全的,然而你又想把InPtr直接赋值给String,那可以用一个中间类来做隐式转换,如下所示:
    class aaa
    {
        [DllImport(@"MFCLibrary1.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
        public static extern MyIntPtr Func4();
    }
    
    class Program
    {
        private static void Main(string[] args)
        {
            string zz = aaa.Func4();
            Console.WriteLine(zz);
    
            Console.ReadLine();
        }
    }
    
    public struct MyIntPtr
    {
        public IntPtr Pointer;
    
        public static implicit operator string(MyIntPtr ptr)
        {
            return Marshal.PtrToStringAnsi(ptr.Pointer);
        } 
    }

    2014年3月20日 9:12
  • 你的那个 C++ DLL 是同一个,还是分别编译的两个?

    上面的代码是C++的,编译成MFCLibrary1.dll

    下面的代码是C#的,调用上面的MFCLibrary1.dll中的Func4函数


    虽然你没回答我的问题,但是我也不纠缠了。

    经我测试,我使用 VS 2013 编译的 C++ DLL,无论是使用 .Net 2.0 ,还是 .Net 4.5 的 C# 程序都无法成功调用。

    因此问题不出在 .Net 的版本上,而是 C++ DLL 中分配内存的方式上,如果字符串通过 CoTaskMemAlloc 来分配的话,C# 中可以使用 string 作为返回值;否则只能使用 IntPtr 来得到地址,然后仅仅是转换成 string,而不对 IntPtr 指向的内存调用 CoTaskMemFree 方法。

    2014年3月20日 9:53
  • 转换一下思路即可,既然DLLImport定义时,IntPtr是安全的,然而你又想把InPtr直接赋值给String,那可以用一个中间类来做隐式转换,如下所示:
    class aaa
    {
        [DllImport(@"MFCLibrary1.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
        public static extern MyIntPtr Func4();
    }
    
    class Program
    {
        private static void Main(string[] args)
        {
            string zz = aaa.Func4();
            Console.WriteLine(zz);
    
            Console.ReadLine();
        }
    }
    
    public struct MyIntPtr
    {
        public IntPtr Pointer;
    
        public static implicit operator string(MyIntPtr ptr)
        {
            return Marshal.PtrToStringAnsi(ptr.Pointer);
        } 
    }

    谢谢
    2014年3月21日 3:21