【问题标题】:How to solve a function acting differently based on callsite?如何解决基于调用点不同的功能?
【发布时间】:2019-05-24 04:57:59
【问题描述】:

不知道如何命名标题,所以可以随意重命名,但我遇到的问题是我有一个功能可以在一个项目中工作,但在另一个项目中失败。下面是粗略的伪代码,显示 LibraryProject 中的一个调用有效,而 GameProject 中的调用无效。

ChildClass::do_stuff 中,win32_window HWND 是有效的,而第二个,failed_win32_window 是 null 并且 glfw 抛出一个错误,说它没有被初始化,尽管它已经被初始化(因为第一次 glfw 调用成功我已经手动验证它是):

GLFWError #65537 Happen, The GLFW library is not initialized

这是显示两个项目和文件的伪代码。 GLFW 已正确设置初始化,因为如果我在 LibraryProject 中执行所有 glfw 逻辑,则窗口会正常显示。

//LibraryProject

////library_header.h
class ParentClass {
  GLFW* _mainWindow; //filled in elsewhere in the real code
  HWND getWin32Window() { return glfwGetWin32Window(_mainWindow); }
}

//GameProject

////game_header.h
#include "library_header.h" //from other Project

class ChildClass : public ParentClass {
  void do_stuff() {
    HWND win32_window = this->getWin32Window(); //this works because it goes down into LibraryProject.dll's module
    HWND failed_win32_window = glfwGetWin32Window(_mainWindow); //but literally the same call here doesn't because it happens within GameProject.exe
  }
}

////game_body.cpp

void function_called_elsewhere_in_game() {
    //called from GameProject.exe
    auto child = ChildClass();
    child.do_stuff();
}

我不确定这是否是 glfw 和我的设置的问题,或者只是我对项目和依赖项如何工作的误解。

我尝试过的事情:

  • 下载最新glfw3
  • 重建整个解决方案
  • 切换引用和链接依赖输入

注意事项:

  • 这发生在主线程中,没有其他东西同时使用 glfw。它也可以 100% 重现。
  • glfw3.lib 总是在我的 GameProject 输出文件夹中创建,基于 LibraryProject 中的文件夹
  • 对两个 glfwGetWin32Window 调用中的每一个进行反汇编时,反汇编中的地址都不同,这让我相信它们是同一个库的两个不同副本,但我不确定。
  • 这不是 cocos2d 的问题,我用作启动空白项目并调用 glfwGetWin32Window(..) 的游戏引擎返回一个有效指针,即使在 GameProject 中也是如此,所以有些事情我做错了,但我没有不知道是什么。

展示实际行为的图片。 magnolia_cocos_proj 是 GameProject 并且是我正在运行的 exe,libcocos2d 是我用作 DLL 的 LibraryProject(我不熟悉链接和 dll 的工作原理)。

  1. win32_window has valid value
  2. definition of getWin32Window() to be 100% sure。请注意,该模块现在位于 libcocos2d.dll 中。
  3. after going over the second line, the error throws and the second window is null

【问题讨论】:

  • 您的应用程序是多线程的吗?来自 glfw 文档:大多数 GLFW 函数只能从主线程(调用 main 的线程)调用
  • 除了主线程之外,这些调用都不会发生在任何地方,我会确保编辑问题,谢谢!
  • 诊断非常明确,它表示您的程序尚未调用glfwInit()。在 sn-p 中看不到这样的调用,所以这是可能的。造成这种情况的一个可能原因可能是对一个看起来不像程序入口点的函数使用了名称“main”。如果链接器选择了那个来启动您的程序,那就太糟糕了。选择另一个名字。另一个可能的原因是库不止一次地链接到程序中。如果 LibraryProject 是一个 DLL 项目,则可能会发生这种情况,但它看起来不像一个。
  • @HansPassant glfwInit() 在 LibraryProject 中被调用,我自己可以通过步进验证这一点。 LibraryProject 是一个 dll 项目,然后双链接听起来像是一种可能性。我已经更新了问题以澄清其中一些要点
  • @TankorSmash 请检查您的 Child 构造函数,它不包含 _mainWindow 的副本。如果这样做,您可能可以通过 Parent 访问有效版本,但这并不意味着它在 Child 中已正确初始化。有关示例,请参见 godbolt.org/z/GMxiTC

标签: c++ visual-studio-2013 linker glfw


【解决方案1】:

正如我从“glfw3.lib 始终被创建”中了解到的那样,您使用静态链接。将库静态链接到不同的 dll 和 exe 会导致复制库的所有静态内存。在这种情况下,您应该为 GLFW 使用动态库。我是glfw3dll.lib

【讨论】:

  • 这就是答案!我用新的glfw3dll.lib 替换了一些#pragma comment(lib, "glfw3.lib") 行,并将GLFW_DLL 的定义添加到项目设置中,按照glfw.org/docs/latest/build_guide.html,一切都很好!感谢所有提出建议的人!
【解决方案2】:

出现此错误的主要情况有两种:

GLFWError #65537 Happen, The GLFW library is not initialised

案例一

如果调用了一个 GLFW 函数,除非初始化库,否则将发生上述错误。 So, you need to initialise GLFW before calling any function that requires initialisation

阅读API introduction 以供参考。使用 if-else 语句处理glfwInit() 和错误。

阅读Moving from GLFW 2 to 3也很有用。

案例二

如果您的机器上安装了以前版本的 GLFW,则经常会发生此错误。 GLFW3 不喜欢与安装的先前版本一起运行。 So, delete all the GLFW libraries and linkers and reinstall the latest GLFW 3 from scratch

希望这会有所帮助。

【讨论】:

  • 也许您还没有阅读这部分 OP GLFW 已正确设置初始化,因为如果我在 LibraryProject 中执行所有 glfw 逻辑,则窗口会正常显示。
  • 感谢您的潜在回答!就像 Amadeus 在案例一中所说的那样,GLFW 已正确初始化。对于案例二,我已经尽我所能查看了所有可能的位置,找到了意外包含一个额外的 glfw 文件但我找不到的位置。
猜你喜欢
  • 1970-01-01
  • 2015-09-18
  • 1970-01-01
  • 2014-03-02
  • 2020-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多