2010-09-27 20 views
3

我正在开发一个C++中的DLL,它需要通过(先前建立的)TCP/IP连接使用write()调用来写入一些数据。确切地说,当进程停止时,DLL应该发送一个'进程12345终止于2007-09-27 15:30:42,我的值是131'的消息。如何在流程的最终阶段执行网络IO?

不幸的是,我所知道的用于检测过程结束的所有方式显然都为时过晚,任何网络调用都无法成功。特别是,我尝试以下方法和返回的write()电话-1在任何情况下:

  1. 呼叫从一个全局对象的析构函数write()
  2. 从使用atexit()注册的回调函数调用write()
  3. DllMain调用write()(如果reason参数是DLL_PROCESS_DETACH)。我知道这不是一件安全的事情,但我有点绝望。 :-)

我知道,一个DLL无法检测任何进程关闭(它可能已被长期的进程终止之前卸载),但由于该DLL需要发送关机数据取决于在DLL中的其他代码,这是可以接受的。我基本上在寻找可以安全执行网络IO的最新时刻。

有谁知道如何做到这一点?

回答

0

我建议采取选项3.只要做你的DLL加载/卸载正常,你很好。打电话write()应该工作,我无法解释为什么它不是你的情况。呼叫失败的原因可能是不相关的另一个原因吗?

如果您从主机应用程序手动调用您的DLL函数,它会工作吗?

+1

http://www.microsoft.com/whdc/driver/kernel/DLL_bestprac.mspx记录了许多不应该由DllMain完成(或注定失败)的事情。这是因为当Windows关闭一个进程时,DLL可以以任何顺序卸载,所以可能出现在你的DLL之前卸载了'Ws2_32.dll'的情况。 – rwong 2010-09-27 12:57:26

+0

如果我读了'DllMain'文档,'kernel32.dll'中的(某些)函数(那些不加载其他DLL的函数)可以从'DllMain'中安全地调用。 – 2010-09-27 13:34:23

+0

@ user198397 - 这种方法的问题在于无法保证WInsock尚未关闭和/或从进程中分离出来。 DLL版本的顺序不在OP的控制之中。 @frerich首先需要找出一个可靠的点来呼叫他的套接字。 – 2010-09-27 20:04:28

0

为什么?只需关闭插座。如果这是程序中唯一的关闭,那么在您的描述中必须这样做,它告诉另一端此端正在退出,并且您可以在开始而不是结束时发送进程标识信息。你不应该在退出钩子或静态析构函数中做任何耗时或可能阻塞的事情。

+0

你是对的。然而,我不幸有点不准确:我需要记录更多的信息,而不仅仅是PID。我相应地扩展了我的问题。 – 2010-09-27 13:31:12

0

Winsock使用WSACleanup在哪里关闭?您需要确保您的I/O在发生这种情况之前完成。

你应该能够制定出如果这是通过放置一个断点在Winsock2.dll的Win32调用发生。 DLL的卸载显示在调试窗口的输出中。

+0

我确认在执行write()调用之前,至少没有* my *代码调用WSACleanup()。我的怀疑是其他一些代码(也许在卸载我自己的DLL之前卸载的其他一些DLL)在清除我的数据之前将所有套接字API断开。也许WinSock DLL本身在卸载之前被卸载,我不知道。 – 2010-09-27 14:02:22

+0

@Frerich - 请参阅编辑 – 2010-09-27 14:18:57

2

请考虑使用Windows Job Objects

您的主程序(监控程序,它将使用例如send())可以启动子进程挂起,将其放入作业,然后恢复。然后它将在作业对象中运行。您可以通过SetInformationJobObjectJobObjectAssociateCompletionPortInformation注册通知。然后你会得到通知,如果在工作中会创建一些子进程,并且如果内部的某个进程将被终止。因此,您将能够从监控进程发送所有您需要的内容。如果您在Visual Studio中调试程序,它还会使用作业对象来控制您的流程以及您启动的所有子流程。

我成功地在C++和C#中使用了这项技术。所以如果你在实现中遇到问题,我可以发布一个代码示例。