Search code examples
c++comvisual-studio-2015atlregsvr32

Why does regsvr32 fail after upgrading an ATL project to VS2015.1?


In my current project I have multiple ATL projects that depend on each other. One of them is called "Common" and defines a trace category, other projects might use to print out trace information.

I defined the category from the IDL file like so:

cpp_quote("static ATL::CTraceCategory DATA_LAYER(_T(\"Data Layer\"), 1);")

Basically this translates to the following definition inside the common header file, other projects include to get informed about the interfaces of the "Common" project.

static ATL::CTraceCategory DATA_LAYER(_T("Data Layer"), 1);

Now since Visual Studio 2013 there appears to be a change in how tracing works.

This does cause source-breaking changes in some uses of the ATL::CTraceCategory class, which will require changes in source code when migrating to Visual Studio 2013.

And indeed, I had to change the line above by removing the second parameter:

cpp_quote("static ATL::CTraceCategory DATA_LAYER(_T(\"Data Layer\"));")

Now everything builds again, but the problem raises as soon as I try to rebuild any project that uses the trace category. After the build successfully finished, the compiler automatically registers the component. And during regsvr32 /s "C:\...\Common.dll" I always receive an debug assertation like this:

Microsoft Visual C++ Runtime Library

Debug Assertion Failed!

Program: ...\x64\Debug\Common.dll

File: c:\program files (x86)\microsoft visual studio 14.0\vc\atlmfc\include\atltrace.h

Line: 337

Expression: false && "Too many categories defined"

This also happens when I try to register the component manually. Only projects that do not depend on the common project and therefor not use any trace category are registered successfully.

Does anybody have a solution for this? I would also accept a solution that shows another way of tracing in ATL, since there does not appear to be any difference to using DebugOutputString instead (If I understood the linked blog correctly).


Solution

  • Okay, I finally figured this out. The problem was related to the declaration of the trace category as static. I have no idea why this built in previous versions of Visual Studio. Anyway, here's the fix: First of all, I changed the definition of the trace category inside my Common.idl file:

    cpp_quote("#ifdef DEFINE_EXPORTS")
    cpp_quote("__declspec(dllexport) extern ATL::CTraceCategory DATA_LAYER;")
    cpp_quote("#else // DEFINE_EXPORTS")
    cpp_quote("__declspec(dllimport) ATL::CTraceCategory DATA_LAYER;")
    cpp_quote("#endif // DEFINE_EXPORTS")
    

    As you can see, the trace category now exports to the library, if DEFINE_EXPORTS is defined, which is true for the common project. All projects referencing this library are importing the definition (by including Common.h, which get's created from the idl file). If you define the trace category as static, each library defines a category on it's own. I think that was the cause for the error I was facing.

    Now inside the dllmain.cpp file of the common project I define the trace categories:

    #if (_MSC_VER >= 1800)
    ATL::CTraceCategory DATA_LAYER(_T("Data Layer"));
    #else
    ATL::CTraceCategory DATA_LAYER(_T("Data Layer"), 1);
    #endif
    

    Note that the code switches between two constructors based on the VC++ version it is compiled with. It should be possible to get rid of this by using the CTraceCategoryEx template, but I stick to this method for now.

    Finally all I had to do was adding the Common.lib reference to the Additional Dependencies of the projects referencing it.