Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/133.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
返回C++;来自Windows DLL的对象 由于微软在运行时的非DLL版本中实现堆,所以从DLL返回C++对象会导致问题: // dll.h DLL_EXPORT std::string somefunc();_C++_Windows_Dll - Fatal编程技术网

返回C++;来自Windows DLL的对象 由于微软在运行时的非DLL版本中实现堆,所以从DLL返回C++对象会导致问题: // dll.h DLL_EXPORT std::string somefunc();

返回C++;来自Windows DLL的对象 由于微软在运行时的非DLL版本中实现堆,所以从DLL返回C++对象会导致问题: // dll.h DLL_EXPORT std::string somefunc();,c++,windows,dll,C++,Windows,Dll,以及: 如果DLL和EXE都是使用多线程DLL运行库构建的,则上述代码运行良好 但是,如果DLL和EXE是在没有DLL运行时库(单线程或多线程版本)的情况下生成的,则上述代码会失败(在调试运行时,由于断言\u CrtIsValidHeapPointer(pUserData))的缘故,代码会立即中止失败;在非调试运行时,堆会损坏,程序最终会在其他地方失败) 两个问题: 有没有办法解决这个问题,然后要求所有代码都使用DLL运行时 对于将其库分发给第三方的人,您如何处理?在API中不使用C++对象吗?

以及:

如果DLL和EXE都是使用多线程DLL运行库构建的,则上述代码运行良好

但是,如果DLL和EXE是在没有DLL运行时库(单线程或多线程版本)的情况下生成的,则上述代码会失败(在调试运行时,由于断言
\u CrtIsValidHeapPointer(pUserData))的缘故,代码会立即中止
失败;在非调试运行时,堆会损坏,程序最终会在其他地方失败)

两个问题:

  • 有没有办法解决这个问题,然后要求所有代码都使用DLL运行时
  • 对于将其库分发给第三方的人,您如何处理?在API中不使用C++对象吗?是否要求库的用户使用DLL运行时?还有别的吗
  • 有没有办法解决这个问题,然后要求所有代码都使用DLL运行时

    据我所知没有

    对于将其库分发给第三方的人,您如何处理?在API中不使用C++对象吗?是否要求库的用户使用DLL运行时?还有别的吗


    在过去,我发布了一个带有DLL的SDK,但它是基于COM的。使用COM,所有参数和IPC的编组都会自动完成。用户也可以通过这种方式与任何语言进行集成。

    有一种方法可以解决这一问题,但这并不简单。与库的大多数其余部分一样,
    std::string
    不直接使用
    new
    分配内存,而是使用分配器(
    std::allocator
    ,默认情况下)


    您可以提供自己的分配器,该分配器使用DLL和可执行文件共有的堆分配例程,例如使用
    HeapAlloc
    获取内存,并从那里子分配块。

    如果您有一个要分发的DLL,并且不想将调用者绑定到C运行时的特定版本,请执行以下任一操作:

    I.将DLL链接到C运行时库的静态版本。从Visual Studio项目属性页中,选择配置属性->C/C++->代码生成的选项卡。这是一个选择“运行库”的选项。选择“多线程”或“多线程调试”而不是DLL版本。(命令行等效为/MT或/MTd)

    这种方法有两个不同的缺点:

    a。如果Microsoft发布了CRT的安全修补程序,则在重新编译和重新显示二进制文件之前,您附带的组件可能会受到攻击

    b。DLL中由“malloc”或“new”分配的堆指针不能由EXE或其他二进制文件“free”d或“delete”d。否则你会崩溃的。fopen创建的文件句柄也是如此。您不能在DLL中调用fopen并期望EXE能够在其上关闭。再说一次,如果你这样做了,就崩溃。您需要构建DLL的接口,以适应所有这些问题。对于初学者来说,将实例返回到std::string的函数可能会成为一个问题。提供DLL导出的函数,以根据需要处理资源的释放

    其他选择:

    二,。发货时不依赖于c运行时。这有点难。您首先必须从代码中删除对CRT的所有调用,提供一些存根函数来链接DLL,并指定“无默认库”链接选项。这是可以做到的


    使用COM接口指针可以从DLL中干净地导出C++类。您仍然需要解决上面1a中的问题,但是ATL类是消除COM开销的一个好方法。

    您的代码有两个潜在问题:您解决了第一个问题—CRT运行时。这里还有另一个问题:std::字符串可能会在VC++版本之间更改。事实上,过去确实发生了变化

    安全的处理方法是只导出C基本类型。并从DLL导出创建和释放函数。导出指针,而不是导出std::string

    __declspec(export)  void* createObject()
    {
         std::string* p = __impl_createObject();
         return (void*)p;
     }
    
    __declspec(export)  void releasePSTRING(void* pObj)
    {   
         delete ((std::string*)(pObj));
    }
    

    <> P>这里简单的事实是,微软的实施是一旁的,C++不是ABI。不能在任何平台上从动态模块导出C++对象,并期望它们与不同的编译器或语言一起工作。


    从DLL导出C++类是一个很大的无意义的操作——因为名字的缩写,在C++中,对于动态加载类缺乏支持——必须静态加载DLL——因此,您将将项目拆分为DLL的最大好处是只需要按需加载功能。不幸的是,我们还需要用于各种Posix操作系统的库版本,因此我需要避免使用MS特定技术。@Jerry-接受您的回答,因为您提供了可行的替代解决方案。有点晚了,但是值得一提的是Jerry的答案:自定义分配器可以捕获当前翻译单元的分配函数

    operator new
    operator delete
    ,从而将分配器“绑定”到原始DLL。看看我多年来成功使用的。在整个项目中,我使用了
    typedef std::basic_string mystring
    而不是
    std::string
    /
    std::wstring
    “只根据需要加载功能的能力”确实是一个好处。但将代码放入DLL(即使它们一直都在加载)可以简化产品维护和支持,因此这是一种更广泛使用的模式。这是怎么回事?认真地在C++开发的上下文中,DLL的使用受到特别限制:-实际上,从第一类中的DLL导出C++类可以继承一种方式,要求DLL始终静态链接,并且所有DLL(和EXES)总是在一起响应于任何CL的改变而重新构建。
    __declspec(export)  void* createObject()
    {
         std::string* p = __impl_createObject();
         return (void*)p;
     }
    
    __declspec(export)  void releasePSTRING(void* pObj)
    {   
         delete ((std::string*)(pObj));
    }