我们有一个拥有许多进程的企业系统(EXE,服务,DCOM服务器,COM +应用程序,ISAPI,MMC管理单元),所有这些都使用了许多COM组件。我们最近看到一些客户部署失败,但发现很难解决问题。
为了追踪问题,我们使用发生错误的日志记录来扩充整个源代码。
为了识别哪些日志来自哪些进程,C ++日志代码(编译到所有组件中)使用EXE名称来命名日志。这对某些情况很有用,但不是全部 - COM +应用程序,ISAPI和MMC管理单元都有系统EXE名称,日志最终交错。
我看到this post about shared data sections可能有所帮助,但我不明白的是谁决定共享部分的内容。有没有什么办法可以保证特定的代码片段在其他人读取之前写入共享部分?
或者这个问题有更好的解决方案吗?
答案 0 :(得分:1)
要同步写入共享部分的多个进程,您需要某种IPC,例如: Windows事件,互斥锁,套接字。每个模块都调用CreateMutex并传递一个固定名称,所有模块共享该名称。模块然后调用WaitForSingleObject来等待并声明互斥锁 - 当其中一个获取它时,它可以在每个其他模块等待时读/写共享部分。完成后,它调用ReleaseMutex让另一个模块继续运行。
说完所有这些,我坚持使用日志文件。我猜您的问题是,对于DLL,您的日志文件名是基于父进程EXE名称而不是DLL自己的名称?
您可以通过存储在DllMain中传递的DLL实例句柄,然后将其与GetModuleFileName一起使用来获取DLL自己的名称。请注意,如果将实例句柄保留为NULL,这也适用于EXE。
// global variable to store DLL handle (or it stays NULL if this is an EXE)
HINSTANCE hDllHandle=NULL;
BOOLEAN WINAPI DllMain( IN HINSTANCE hInstance,
IN DWORD nReason,
IN LPVOID Reserved )
{
hDllHandle = hInstance;
return TRUE;
}
<snip>
void Log(LPSTR lpszMsg)
{
WCHAR szMyModuleName[MAX_PATH]={0};
// if hDllHandle is still NULL (e.g. this is an EXE) it returns the process name
// if non-NULL, it returns our DLL name
GetModuleFileName(hDllHandle, szMyModuleName, MAX_PATH);
fprintf(LOGFILE, "[%s] %s\n", szMyModuleName, lpszMsg);
....<snip>....
}
答案 1 :(得分:0)
在DLL中使用共享部分(带有RWS标志的部分)并不能真正解决您的主要问题。如果您需要共享内存以便在进程之间进行快速通信,则可以使用内存映射文件(例如,请参阅http://msdn.microsoft.com/en-us/library/ms810613.aspx),并且可以更好地控制共享内存的创建和使用。
要接收有关加载DLL的进程的更多信息,您可以另外记录应用程序的命令行(例如GetCommandLine()
函数)。您将看到类似“C:\ Windows \ system32 \ mmc.exe C:\ Windows \ system32 \ services.msc”或“C:\ Windows \ system32 \ mmc.exe C:\ Windows \ system32 \ azman.msc”的内容对于MMC snapins。
要查看有关调用流程的更多信息,您可以StackWalk64
(请参阅http://msdn.microsoft.com/en-us/library/ms680650(VS.85).aspx)功能。有关一个好的代码示例,请参阅http://stackwalker.codeplex.com/或http://www.codeproject.com/KB/threads/StackWalker.aspx。