views:

44

answers:

2

Hi all,

We've got an Enterprise system which has many processes (EXEs, services, DCOM servers, COM+ apps, ISAPI, MMC snapins) all of which make use of many COM components. We've recently seen failures in some of the customer deployments, but are finding it hard to troubleshoot the cause.

In order to track down the problem, we've augmented the entire source with logging statements where errors occur.

In order to identify which logs came from what processes, the C++ logging code (compiled into all components) uses the EXE name to name the log. This is good for some cases, but not all - COM+ apps, ISAPI and MMC snapins all have system EXE names and the logs end up interleaved.

I saw this post about shared data sections which might help, but what I don't understand is who decides what goes in the shared section. Is there any way I can guarantee that a particular piece of code writes into the shared section before anyone else reads it?

Or is there a better solution to this problem?

A: 

To synchronize multiple processes writing to the shared section you'd need some kind of IPC e.g. Windows events, mutexes, sockets. Each of your modules calls CreateMutex and passes a fixed name which all the modules share. Modules then call WaitForSingleObject to wait and claim the mutex - when one of them gets it, it can read/write the shared section while every other module waits. When its done it calls ReleaseMutex to let another module have a go.

Having said all that personally I'd persevere with the log files. I'm guessing your problem is that for DLLs you're basing your log file name on the parent process EXE name instead of the DLLs own name?

You can get a DLLs own name by storing the DLL instance handle you get passed in DllMain, and then using it with GetModuleFileName. Note this works for EXEs as well if you leave the instance handle as NULL.

// 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>....
}
snowcrash09
Thanks for the info so far. Yes, this is where we're getting stuck. It's hard to predict the EXE name as the DLL's could be hosted by any ActiveX host, although there is usually a 'main' DLL in these cases.. which led me to the shared data section idea. I guess I need something like 'GetMainModuleFileName()' which would determine the 'main' DLL or use the EXE name if there isn't one.. any ideas?
JBRWilkinson
Hi - surely the code I posted above gives you exactly that - if its linked into a DLL running in a host process it tells you the name of your DLL, otherwise it tells you the name of your .exe. Apologies if I've missed something.
snowcrash09
So the 'main' DLL would have a DllMain which sets hDllHandle.. and other DLLs don't. How do the other DLL's know to all reference the exact same hDllHandle variable?
JBRWilkinson
Sorry, I was assuming you'd give every DLL it's own DllMain and hence its own unique hDllHandle. That would let enable you to create one logfile for every DLL, with filename based on the DLL name.
snowcrash09
A: 

Hi!

Usage of a shared section in a DLL (section with the RWS flags) don't really solve your main problem. If you need a shared memory for quick communication between processes you can use memory mapped files (see http://msdn.microsoft.com/en-us/library/ms810613.aspx for example) and have more control over creating and usage of the shared memory.

To receive more about the process which loaded your DLL you can log additionally a command line of the application (GetCommandLine() function for example). You will see something like "C:\Windows\system32\mmc.exe C:\Windows\system32\services.msc" or "C:\Windows\system32\mmc.exe C:\Windows\system32\azman.msc" for MMC snapins.

To see more information about calling process you can you StackWalk64 (see http://msdn.microsoft.com/en-us/library/ms680650(VS.85).aspx) function. See http://stackwalker.codeplex.com/ or http://www.codeproject.com/KB/threads/StackWalker.aspx for a good code example.

Oleg