如何在 VC++ 2015 全程序优化存在的情况下正确暴露来自 dll 的接口

How to correctly expose interfaces from a dll in the presence of VC++ 2015 whole program optimization

最近我们在目前从 VS2010 移植到 VS2015 的遗留代码中遇到了一个有趣的效果。不幸的是,我无法创建一个小示例来展示这种效果,但我会尽可能准确地描述它。

我们有 2 个 dll(我称它们为 dll A 和 dll B)。 dll A 的项目定义接口 IFoo 和派生接口 IFxFoo

class __declspec(novtable) IFoo {
public:
    virtual int GetType() = 0;
    virtual ~IFoo() {}
};

class __declspec(novtable) IFxFoo : public IFoo {
public:
    virtual int GetSlot() = 0;
};

在dll B中,两个接口都用到了。

class CBImpl : public IFxFoo {
public:
    ...
    void processFoo(IFoo* f) {
        ...
        if (f->GetType() == IFXFOO) {
            IFxFoo* fx = static_cast<IFxFoo>(f); //downcast
            fill(fx);
        }
    }

    void fill(IFxFoo* fx) {
        m_slot = fx->GetSlot();
    }
private:
    int m_slot;
};

processFoo() 将使用不同的 IFoo 实现调用。一些来自 dll A,一些来自 dll B。

现在发生的事情如下: - 如果我们在编译 dll B 时打开了整个程序优化,函数 fill() 中对虚函数 GetSlot() 的调用将被 Visual C++ 去虚拟化。这导致我们的程序崩溃。 如果我们可以解决这个问题

我现在的问题是:

感谢您的帮助 托拜厄斯

使用 LTO 会导致编译器对它能够看到完整调用图的任何函数进行大幅调整。

您所看到的是预期的,并且在需要从单独模块使用的函数上使用 __declspec(dllexport)extern 或将它们显式声明为 DLL .def 文件的一部分是解决问题的预期方法,因为编译器将不再将函数视为仅供内部使用。