Visual Studio 2005 Preprocessor #defines not being inherited

So I come across a situation where I'd like to modify a set of macros based on the project that has included a given header file.

 

Ugly background - Migrating code from visual studio 6 to visual studio 2005 in pieces.  Some common pieces are still in vc6, which used a compiler that didn't have the extremely NIFTY variadic macros feature introduced in the VC++ compiler in VS2005.  Variadic Macros = macros that accept a variable number of arguments.

 

Anyway, so I have defined my preprocessor #define at the project level but for some reason the code keeps running as though the #define isn't defined!  If I manually include a #define ... then the code picks it up (depending on where the manual #define is placed).  Am I running up against the "30 preprocessor defines via /D" compiler limitation?  No, a quick look at the command-line shows fewer than 10 in total.

 

Turns out that because this particular project was migrated from Visual Studio 2003 a wonderful $(NoInherit) tag was added to the compiler call for each file inside the .vcproj file.  Of course this tag isn't exposed through the UI.  Googling revealed that $(NoInherit) did exactly what it sounded like - it inhibits inheriting of the corresponding project level property.  In this case, it was preventing my project level #define from propagating to the compilation command (cl.exe).

 

ARGH!!!!!!

PERL, like riding a bicycle

I haven't written PERL for pay in several years but a popular wiki tool that I'm using (TWiki) uses it.  So on occasion I have to jump back into the PERL world.  A few quick hits that should help me (and you) get up to speed quickly when tracking down a problem.  I'm using indigoperl on win32 with several of the win32 ports of GNU tools (e.g., less)

 

Getting Help


Thank goodness for perldoc.  Executed via perldoc

or perldoc .  Useful perldoc pages:

  • perltoc - table of contents
  • perlintro - quick syntax reference (see perlsyn for more detail)
  • perlfunc - list of builtin functions
  • perldebtut - perl debugger tutorial.  Covers the basics more than well enough to troubleshoot most problems.

Useful Debugger Commands


Phrased in "Visual Studio" speak for those of us in the Win32 world now..


  • n - step over
  • s - step into
  • r - step out
  • v - display surrounding source code, type again to display more source code
  • . - show next statement
  • c - run until line (the line numbers are listed by v or l)
  • l - list line
  • p $var - prints $var (scalar).
  • x @var - prints @var in a list context
  • x \%var - pretty prints name/value pairs for a hash, also prints any object.

Turns out my particular problem was inside CharsetDetector::detect1().  It was dying when it encountered certain byte sequences.  Quick and dirty solution was to wrap it inside an eval { } (PERL's faked exception handling mechanism - errors stored in $@) then return an empty string.

 

 

Registration free COM for .Net and Native components

On XPSP2 it appears that manifests (assembly and application) need to be both embedded AND standalone.

 

The SideBySide assembly manager puts errors that occur during load into the System event log (on windows XP).  The errors are listed in reverse order so the last one is the most general and earlier ones are more specific.  This has proven invaluable in tracking down Side by Side assembly problems.  Apparently Windows Vista has an sxstrace tool that improves on this but I'm presently stuck on XP...

 

An error message along the lines of "Component identity does not match component requested" was, in my case, traced back to a missing "type=win32" attribute for the assemblyIdentity element.

 

 

Wonderful ISO mounting utility

There are lots of programs out there that enable creation and mounting of ISO images (and other image formats as well). One of my favorites, Alcohol, requires the installation of a "fake" SCSI driver that occasionally interacts poorly with other drivers.

I ran across a wonderful ISO mounting utility directly from Microsoft! It doesn't even support adding a driver to the bootup sequence so it has no impact on startup time. It's not terribly polished - I've found that you can cause it to malfunction if you don't give it time to execute its operations - but it's free, extremely compact and comes directly from The Source (Microsoft). It's called the
Virtual CDRom Control Panel (even though it doesn't really look like a control panel).

Registration Free COM for unmanaged components

By unmanaged components I mean COM servers built with unmanaged/native frameworks; ATL, MFC or (heaven forbid) Win32.

Getting Registration Free COM to work on Windows XP for unmanaged components is similar to getting Registration Free COM to work for managed components.  I'm finding that having the manifest as a standalone file helps a lot during debugging and for managing changes.  Visual Studio 2005 has options for setting a lot of these properties (e.g., assembly identity, dependency fragments, etc...) but I've found it easier to keep them in a single file (included in the project but NOT ending in .manifest because these files are merged no matter what).

The key insight for me was that assembly, in this context, doesn't mean the same thing as an assembly in the managed context.  An assembly is a logical grouping of of Portable Executable (PE) modules (.exes, .dlls, etc...).  It can contain 1 or more DLLs but it's something that the developer creates to control the code that gets executed at runtime (in this case by controlling which module the COM runtime binds to the application).

It MUST have a different name than any of the DLLs (really PEs but you get the point) it contains.  As an example (below), I created an assembly named TestATLLib.X that contains 1 PE - TestATLLib.dll.  That assembly uses the following assembly manifest:


<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
manifestVersion="1.0">
<assemblyIdentity
type="win32"
name="TestATLLib.X"
version="1.0.0.0" />
<file name = "TestATLLib.dll">
<comClass
clsid="{EBB0B140-09E7-4C47-B6F1-FACD79FA0F55}"
threadingModel = "Apartment" />
<typelib tlbid="{CC66CB00-53FB-41F3-A745-28D467ED7523}"
version="1.0" helpdir=""/>
</file>
<comInterfaceExternalProxyStub
name="ITestSimpleObj"
iid="{C066CE71-F97C-4CA6-8769-72114D3DDC71}"
proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"
baseInterface="{00000000-0000-0000-C000-000000000046}"
tlbid = "{CC66CB00-53FB-41F3-A745-28D467ED7523}" />
</assembly>







Use project properties -> Manifest Tool -> Input and Output: Additional Manifest Files to have this merged into the automatically generated manifest.  I also set an Output Manifest file ($(OutDir)\$(ProjectName).X.manifest so that I can copy it to the application executable directory after building the application.  The standalone manifest file shouldn't be necessary but I believe there's a problem on Windows XP that prevents that binding process from using the embedded manifest for DLLs.



Now that the unmanaged COM object has been wrapped into an assembly and that assembly has been named and versioned registration free COM requires that the application declare that it depends on the assembly.  This is done with another manifest file (this time an application manifest).  I tested it with a managed client because that's the easiest for me to make but it should work from any client executable.





The application manifest below declares that TestClient needs assembly TestATLLib.X.  Whereas COM usually requires its DLLs to be registered, this test executable will run without the COM object being registered! 



<?xml version="1.0" encoding="UTF-8" standalone="yes"?>


<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">


<assemblyIdentity type="win32"
name="TestClient"
version="1.0.0.0" />


<dependency>


<dependentAssembly>


<assemblyIdentity type="win32"
name="TestATLLib.X"
version="1.0.0.0"/>


</dependentAssembly>


</dependency>


</assembly>









Although you can embed the application manifest in the executable as a native win32 resource I have tended to place it alongside the executable (it must have the same name as the executable with the additional .manifest extension - so TestClient.exe's application manifest is stored in TestClient.exe.manifest).

Registration Free COM for .net/managed components

.NET assemblies can be used from native code via COM.  Unfortunately COM, by default, uses the shared assembly model.  That is, everyone using a given version of a COM server uses the executable (or dll) stored in the same place.  So the last app to install the COM component determines which COM executable is used; if that app is uninstalled all the other apps that depended on that component are broken.

To get around this problem Registration Free COM was introduced.  Now that computers have so much memory one of the main benefits of shared assemblies/shared dlls is no longer relevant.  And the problem of DLL hell is much mitigated when every application has it's own copy of the DLLs it uses.

The excellent article "Registration-Free Activation of .NET-Based Components: A Walkthrough" got me about 3/4ths of the way there but I didn't like having to manually compile a project so as to embed the .net component's manifest as a native win32 resource in the resulting executable.

Fortunately, another blog post "How to embed a manifest in an assembly: Let Me Count The Ways..." points out how to use the manifest tool (mt.exe) included in the 2.0 SDK and vs2005 to embed the resource after the assembly has been built (e.g., a post build event).

I got this working on a small test project.  The key components were as follows:

Native application manifest:

<?xml
version="1.0"
encoding="utf-8"?>
<assembly
xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="CppClient" version="1.0.0.0" />
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="RegFreeCSharpClassLibrary"

version="1.0.0.0"/>

</dependentAssembly>
</dependency>
</assembly>








This should be added to the generated manifest via Project Properties -> Manifest Tool -> Input and Output -> Additional Manifest Files.  Be sure not to name it with the .manifest extension until you've verified that it work; visual studio 2005 always includes any files in the project that end with the .manifest extension.





NOTE:  Since I'm using Windows XP I couldn't get the native application manifest to work when it was embedded in the executable but it works as a standalone .exe.manifest file alongside the executable.





For the managed component that was being exposed via COM, the manifest was as follows:




<?xml
version="1.0"
encoding="UTF-8" standalone="yes"?>

<assembly
xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="RegFreeCSharpClassLibrary"
version="1.0.0.0" />
<clrClass clsid="{684DFB01-D74F-41c7-95F9-6520C910BF18}" name="RegFreeCSharpClassLibrary.MyClass"></clrClass>
</assembly>






This manifest needs to be converted into a binary win32 resource then embedded into the resulting executable via the manifest tool mt.  In a post build event this can be done as follows:





mt.exe" -manifest "$(ProjectDir)$(TargetName).manifest"  –outputresource:"$(TargetPath)";#1