安全地在c ++中的dll边界之间传递数据

时间:2017-05-13 07:30:14

标签: c++ c dll cross-compiling

让结构

struct MyDataStructure
{
    int a;
    int b;
    string c;
};

让dll公开的接口中有一个函数。

class IDllInterface
{
    public:
       void getData(MyDataStructure&) = 0;
};

从加载dll的客户端exe,以下代码是否安全?

...
IDllInterface* dll = DllFactory::getInterface(); // Imagine this exists
MyDataStructure data;
dll->getData(data);
...

当然,假设客户端和dll都知道MyDataStructure。另外根据我的理解,由于代码是针对dll和exe单独编译的,因此对于差异编译器/编译器版本,MyDataStructure可能不同。我的理解是否正确。

如果是这样,在使用不同的编译器/编译器版本时,如何安全地在dll边界之间传递数据。

3 个答案:

答案 0 :(得分:1)

您可以使用“协议”方法。为此,您可以使用内存缓冲区来传输数据,双方只需要就缓冲区布局达成一致。

协议协议可能类似于:

  1. 我们不使用结构,我们只使用内存缓冲区 - (传递一个指针或任何工具包允许共享内存缓冲区。
  2. 在设置任何数据之前,我们将缓冲区清除为0。
  3. 所有整数在缓冲区中使用4个字节。这意味着每一方使用其编译器下的任何int类型为4字节,例如INT /长。
  4. 对于两个整数的特殊情况,前8个字节有整数,之后就是字符串数据。

    #define MAX_STRING_SIZE_I_NEED 128

    // 8 bytes for ints.

    #define DATA_SIZE (MAX_STRING_SIZE_I_NEED + 8)

    char xferBuf[DATA_SIZE];

  5. 所以Dll设置int等,例如

    void GetData(void* p);
    
    // "int" is whatever type is known to use 4 bytes
    
    (int*) p = intA_ValueImSending;
    (int*) (p + 4) = intB_ValueImSending;
    strcpy((char*) (p + 8), stringBuf_ImSending);
    

    在接收端,将缓冲的值放在struct中是很容易的:

    char buf[DATA_SIZE];
    void* p =(void*) buf;
    theDll.GetData(p);
    theStrcuctInstance.intA = *(int*) p;
    theStrcuctInstance.intB = *(int*) (p + 4);
    ...
    

    如果你想要你甚至可以就每个整数字节的字节顺序达成一致,并设置缓冲区中每个整数的4个字节中的每个字节 - 但你可能不需要达到那个程度。

    为了更一般的目的,双方可以就缓冲区中的“标记”达成一致。缓冲区看起来像这样:

    <marker>
    <data>
    <marker>
    <data>
    <marker>
    <data>
    ...
    

    Marker:第1个字节表示数据类型,第2个字节表示长度(非常像网络协议)。

答案 1 :(得分:1)

如果要在COM中传递字符串,通常需要使用COM BSTR对象。您可以使用SysAllocString创建一个。这被定义为在编译器,版本,语言等之间保持中立。与流行的看法相反,COM直接支持int类型 - 但从它的角度来看,int始终是32位类型。如果你想要一个64位整数,那就是Hyper,用COM说话。

当然,您可以使用您的连接双方都知道/理解/同意的其他格式。除非你有非常这样做的理由,否则几乎肯定是一个糟糕的主意。 COM的主要优势之一就是你似乎想要的那种互操作 - 但是发明你自己的字符串形式会大大限制它。

答案 2 :(得分:0)

使用JSON进行通信。

我认为我找到了一种更简单的方法来回答自己的问题。正如@Greg的答案所建议的那样,必须确保数据表示遵循一种协议,例如网络协议。这样可以确保不同二进制组件(此处为exe和dll)之间的对象表示形式无关。如果我们再考虑一下,这就是JSON通过定义简单的对象表示协议解决的相同问题。

所以对我来说,一个简单而强大的解决方案是从exe中的对象构造一个JSON对象,对其进行序列化,以字节为单位跨dll边界传递,并在dll中反序列化。 dll和exe之间唯一的协议是它们都使用相同的字符串编码(例如UTF-8)。

https://en.wikibooks.org/wiki/JsonCpp

一个人可以使用上面的Jsoncpp库。默认情况下,字符串在Jsoncpp库中由UTF-8编码,因此也很方便:-)