简体   繁体   English

当通过C#调用C ++ DLL的导出类时,该类的C风格字符串成员在一个导出函数中是正常的,但在另一个导出函数中则没有

[英]When calling an exported class of a C++ DLL by C#, C-style string members of the class are OK in one exported function, but not in the other

C++ console calls DLL OK, but not C#. C ++控制台调用DLL OK,但不调用C#。

In the exported function setInputs , the const char* -type public member of class object is set OK, but in the exported function run , it becomes some meaningless characters. 在导出的函数setInputs ,类对象的const char* -type公共成员设置为OK,但在导出的函数run ,它变成了一些无意义的字符。

exported DLL: 导出的DLL:

namespace{
    CLASS*CLASS_Ptr_Object=new CLASS();
    }

extern "C" __declspec(dllexport)
void setInputs(char*char_Ptr_Model,int int_Type){
        CLASS_Ptr_Object->m_char_Ptr_Input_Model=char_Ptr_Model;//when I print the public member m_char_Ptr_Input_Model, I see it is OK here
        CLASS_Ptr_Object->m_int_Type=int_Type;//int and double types are always OK
}

extern "C" __declspec(dllexport)
void run(){
    CLASS_Ptr_Object->run();//when I print the public member m_char_Ptr_Input_Model, I observe it has become some meaningless characters, although it was OK in previous exported function
}

how the public member is defined in header file: 如何在头文件中定义公共成员:

class CLASS
    {

    //...

    public:
        const char*m_char_Ptr_Input_Model;
    };

Invoke in C#: 在C#中调用:

[DllImport(@"DLL.dll", EntryPoint = "setInputs")]
        public static extern setInputs(
            [In, Out, MarshalAs(UnmanagedType.LPStr)]string char_Ptr_Model
            , [In, Out, MarshalAs(UnmanagedType.I4)]int int_Type
             );

 [DllImport(@"DLL.dll", EntryPoint = "run")]
 public static extern run();

The content of the character buffer that supplied by the C# marshaller is only valid for the duration of the call to setInputs . 由C#marshaller提供的字符缓冲区的内容仅在调用setInputs期间有效。 As soon as setInputs finishes, referring to that buffer is invalid. 一旦setInputs完成,引用该缓冲区就是无效的。

The marshaller creates a temporary buffer to hold the character array, converts from the UTF-16 .net string to an 8 bit string. 编组器创建一个临时缓冲区来保存字符数组,从UTF-16 .net字符串转换为8位字符串。 And then calls setInputs passing the address of the temporary buffer. 然后调用setInputs传递临时缓冲区的地址。 When setInputs returns, the temporary buffer is destroyed. setInputs返回时,将销毁临时缓冲区。 But you've held on to the address of that buffer and now you have a pointer to who knows what. 但是你已经掌握了缓冲区的地址,现在你有一个指向谁知道什么的指针。

You will need to take a copy of the string. 您需要获取该字符串的副本。 The simplest way is to declare the member to be of type std::string and use the assignment operator that accepts a const char* assignment source. 最简单的方法是将成员声明为std::string类型,并使用接受const char*赋值源的赋值运算符。

The problem with your exported DLL function that handles strings is that you're relying that the calling language (in your case C#) handles pointers in the same manner as C++. 您导出的DLL函数处理字符串的问题在于您依赖于调用语言(在您的情况下为C#)以与C ++相同的方式处理指针。 As the answer that David Heffeman has given, you can't assume that the calling language uses the same semantics as a C++ program would use. 作为David Heffeman给出的答案,您不能假设调用语言使用与C ++程序相同的语义。

If the calling program were C++, and if the pointer points to the string after the DLL call, then of course you will see that the DLL pointer also points to the string. 如果调用程序是C ++,并且如果指针在DLL调用后指向字符串,那么当然你会看到DLL指针也指向字符串。 But strings in other languages, and marshaling of such strings to DLL functions can and will work differently than the "simple" C++ model. 但是其他语言中的字符串以及将这些字符串封送到DLL函数可以并且将与“简单”C ++模型的工作方式不同。

Assuming we're not talking about COM, but just generic string handling for non-COM DLL's, if you look at how a typical Windows API function handles strings, it uses one of the following methods: 假设我们不是在谈论COM,而只是非COM DLL的通用字符串处理,如果你看一下典型的Windows API函数如何处理字符串,它会使用以下方法之一:

For accepting strings: 接受字符串:

An LPCTSTR is usually the parameter type, and the Windows API function takes the pointer provided and copies the contents of the buffer to an internal buffer (if that's the purpose of the function). LPCTSTR通常是参数类型,Windows API函数接受提供的指针并将缓冲区的内容复制到内部缓冲区(如果这是函数的目的)。 This could mean storing the value in a char array, or as the answer suggested, stored in a std::string or some other container internal to the DLL. 这可能意味着将值存储在char数组中,或者作为建议的答案存储在std::string或DLL内部的其他容器中。 Thus, when the function returns, the pointer value that was originally passed is no longer referred to -- the data is intact within the DLL. 因此,当函数返回时,不再引用最初传递的指针值 - 数据在DLL中是完整的。

For returning strings: 返回字符串:

An LPTSTR is passed as a parameter, along with a length argument denoting the maximum number of characters to copy from the Windows API function to the buffer. LPTSTR作为参数传递,并带有一个长度参数,表示从Windows API函数复制到缓冲区的最大字符数。 Another variant is that the API function documents how big the buffer should be, and the caller has to ensure that the buffer is big enough. 另一个变体是API函数记录缓冲区应该有多大,并且调用者必须确保缓冲区足够大。 The DLL function then copies the data to the buffer and returns. DLL函数然后将数据复制到缓冲区并返回。

In none of the above scenarios does the DLL store the pointer to the buffer. 在上述任何情况下,DLL都不会将指针存储到缓冲区。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM