运行.exe的main(),作为.dll的一部分

时间:2014-01-22 21:10:39

标签: c++ multithreading

我有一个依赖.dll扩展功能(模块)的应用程序。 我想从另一个程序(这是一个服务器)中嵌入一些特定的功能。

另一个程序有一个相对简单的n-main.cpp

#include <n.h>

int main(int argc, char * argv[])
{
     // creates a listen server and blocks the main thread
     // until it receives SIGKILL/SIGTERM or a custom HTTP header to stop 
     n::start(argc,argv); 
}

所以我这样做了:

#include <modulespecs.h>
#include <mymodule.h> // only some general specs
#include <n.h> // copied from n-main.cpp, no errors

// The main program calls this function to attach the module
void onModuleAttached(){

     // create some fake arguments
     int argc = 2;
     char * argv[] = {"n.exe","someconfig.js"}; 

     // and act as if 
     n::start(argc,argv);
}

到目前为止,这是完美的,服务器已创建,等待传入连接,并正确回答请求。

唯一的问题是,当加载模块时,服务器会阻止主应用程序,因此主应用程序不会继续运行,因为它等待我的模块中的服务器首先结束活动(这不是&#39发生)。即使它确实如此,服务器也有逻辑在死亡时完全关闭主应用程序。

我尝试的事情:

  #include <thread>

  void create_server(){
      int argc = 2;
      char * argv[] = {"n.exe","someconfig.js"}; 

      // and act as if 
      n::start(argc,argv);
  }
  void onModuleAttached(){

      // crashes
      std::thread test(create_server); 

      // creates the server, then exits immediately
      std::thread (create_server).join();

      // same as join()
      std::thread (create_server).detach();
  }

有没有具体的方法来实现这一目标?

1 个答案:

答案 0 :(得分:3)

我猜你是从onModuleLoaded()函数调用DllMain()。在持有OS加载程序锁定时调用DllMain(),因此您应该never do anything scary inside DllMain()。创建线程是一件非常可怕的事情,所以你永远不应该在DllMain()内做到这一点。

避免这种情况的推荐方法是使用单独的DLL入口点来执行可怕的操作,然后记录您的DLL,以便在DLL初始化之后必须调用该入口点。还提供了在卸载DLL之前调用的相应出口例程。

例如:

DLLEXPORT BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    // Nothing much here
}

std::thread server_thread;

DLLEXPORT void StartServer()
{
    server_thread = std::thread(create_server);
}

DLLEXPORT void StopServer()
{
    server_thread.join();
}

然后您的主程序可能如下所示:

// Load the DLL and get its entry and exit routines
HMODULE serverDLL = LoadLibrary(...);
void (*StartServer)() = (void (*)())GetProcAddress(serverDLL, "StartServer");
void (*StopServer)() = (void (*)())GetProcAddress(serverDLL, "StopServer");

// Call the entry routine to start the server on a new thread
StartServer();

// Do other main program stuff
// ...

// We're done now, tell the server to stop
StopServer();
FreeLibrary(serverDLL);