0

i'm using VS2010, and i am designing a MVC application.

Say i have "Project 1" and "Project 2" in a solution. The need to be compiled in that order, P1 compiles to a DLL, P2 to an Exe file that dynamically uses the DLL. P2 declares a view interface. Both projects have a view class that implements the interface (a class with pure virtual methods).

The problem now is, that i cannot include the header file of the interface in P1, because the linker would say then that he cannot resolve this external symbol. Which is of course right, because it is compiled later in P2.

So what i did is, i added the include folder for P2 to P1 and included the interface.cpp in P1 instead of the header file.

It works, but i don't think this is what i am supposed to do. Or isn't it? The interface is obviously compiled twice, once in each project.

I don't want to move the interface to P1, what would solve the problem. Just assume, i don't want that.

Thanks for input.

edit: code snippet:

Project1:

View1.hpp // nothing special

View1.cpp:

#include ViewInterface.cpp
View1::View1(int x) : ViewInterface(int x)

Project2:

ViewInterface.hpp:

#ifdef EXP
#define DECLDIR __declspec(dllexport)
#else
#define DECLDIR __declspec(dllimport)
#endif

class ViewInterface : SomeOtherClass, AnotherClass
{
  virtual void DECLDIR show(void) const = 0;
  virtual void DECLDIR hide(void) const = 0;
}

ViewInterface.cpp:

ViewInterface::ViewInterface(int x) : SomeOtherClass(int x), AnotherClass(int x)

View2.hpp // nothing special

View2.cpp:
#define EXP
#include ViewInterface.h

View2::View2(int x) : ViewInterface(int x)
4

2 回答 2

1

为了让可执行文件使用 DLL 中的类,您需要确保它们被正确导出。编译 DLL 时,用 标记类__declspec(dllexport),而在编译可执行文件时,用 标记类__declspec(dllimport)。通常这是使用如下宏完成的:

// In your DLL's header file
#ifdef COMPILING_MY_DLL
#define MY_EXPORT __declspec(dllexport)
#else
#define MY_EXPORT __declspec(dllimport)
#endif

class MY_EXPORT MyClass
{
    ...
};

然后,在您的 DLL 项目中定义宏COMPILING_MY_DLL.

于 2012-10-24T21:40:51.507 回答
0

我不想将接口移到 P1,什么可以解决问题。只是假设,我不想要那个。

然后将其移动到第三个实体。

你必须决定什么对你更重要。如果您想要一个干净的解决方案,那么要么将接口定义移至 DLL (P1),要么移至 DLL 和 EXE 都可以使用的东西——我们称之为“P0”。P0 甚至不必是已编译的东西——在它自己的目录中的一个简单的头文件,其中所有定义的内容都内联就可以了。我的首选是让 P0 成为一个 DLL。

这是唯一干净的解决方案。为了完整起见,以下“解决方案”实际上只是我描述的黑客。


如果您真的想要“肮脏”的解决方案,那么也可以这样做,唯一的区别是您将定义接口的头文件留在应用程序源文件夹中。

如果你想要它超脏,然后像你建议的那样在构建 DLL 时包含 .cpp 文件。它也会起作用......这真的很糟糕。

当然,有些事情你必须要知道。例如,“接口”不应该有任何静态数据成员,“接口”中的任何函数都不应该有函数局部静态。因为如果他们这样做了,那么这些静态变量将被实例化两次——一次在 DLL 中,一次在 EXE 中。此外,由于所有代码都将编译到两个项目中,因此如果要更改任何内容,则必须重新编译这两个项目。(在 DLL 和 EXE 中重复的代码不是问题,只要它们是从相同的代码编译的。)

如果您选择“P0 = 只是一个头文件”解决方案,这些限制当然也适用。


最后还有一个非常糟糕的超级脏解决方案:在 EXE 中实现接口,从 EXE 中 dllexport 并将其 dllimport 到 DLL 中(是的,可以这样做!)。缺点是您必须执行一个特殊的 EXE 构建,它只构建 EXE 的导入库(这可以在没有 DLL 的导入库的情况下完成)。使用 EXE 的导入库,您可以构建 DLL,然后使用 DLL 的导入库,您可以构建 EXE 本身。这样,“接口”甚至可以具有静态数据成员,如果您只更改代码(即头文件中没有更改),那么您只需要重新编译 EXE。

于 2012-10-24T22:24:30.253 回答