Showing posts with label visual studio. Show all posts
Showing posts with label visual studio. Show all posts

2011-01-18

Manifest this

In this blog entry I will talk about Visual Studio 2008 and the C runtime library.

Firstly we create a new Win32 hello world console application:

#include <iostream>

int main()
{
    std::cout << "Hello World" << std::endl;
}

The resulted hello.exe binary is 9KB large, and by using Dependency Walker we find that is dynamically liked to msvcp90.dll, msvcr90.dll, and kernel32.dll

One might think that in order to deploy this hello application you will only need msvcp90.dll and msvcr90.dll alongside the application, or to have them somehow installed in the system.

The latter option is preferred by most applications, you only need to install Microsoft Visual C++ 2008 Redistributable Package and that's it.

The redistributable package is 1.7MBytes in size, and is installed in c:\Windows\WinSxS directory, and it also includes MFC. But this is just a hello world application, surely we don't need to install MFC.

The good news is that you can copy from C:\Program Files\Microsoft Visual Studio 9.0\VC\redist\x86\Microsoft.VC90.CRT\ only msvcp90.dll, msvcr90.dll, and the funnily file named Microsoft.VC90.CRT.manifest. You don't need to copy msvcm90.dll because this is required for "Managed" C++ applications.

The manifest file is required because starting with Visual Studio 2005 the C runtime library (CRT) is packaged as Side-by-side Assembly. Applications need to have also a bit of magic in order to work with the new CRT namely the RT_MANIFEST resource embedded in the executable.

By using Resource Hacker we can take a peek at this RT_MANIFEST section:

<assembly manifestversion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <trustinfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedprivileges>
        <requestedexecutionlevel level="asInvoker" uiaccess="false"></requestedexecutionlevel>
      </requestedprivileges>
    </security>
  </trustinfo>
  <dependency>
    <dependentassembly>
      <assemblyidentity name="Microsoft.VC90.CRT" processorarchitecture="x86" publickeytoken="1fc8b3b9a1e18e3b" type="win32" version="9.0.21022.8"></assemblyidentity>
    </dependentassembly>
  </dependency></assembly>

I have highlighted the version of  the CRT used.

What happens if you decide to install Visual Studio 2008 SP1? You would expect that you should have a different CRT version. That was the case for Visual Studio 2005, Visual Studio 2008 uses the RTM version also when you install SP1, as described in this Visual C++ Team Blog article.

The size of the Microsoft Visual C++ 2008 SP1 Redistributable Package changed as well, from 1.7MB to 4.0MB due to MFC Facelift... Feature Pack and C++ TR1 inclusion.

In order to have the new CRT referenced one needs to set the following preprocessor define _BIND_TO_CURRENT_CRT_VERSION. After doing so the CRT version becomes 9.0.30729.1.

After Visual Studio 2008 SP1 there was another CRT update due to ATL Security Update, which bumped the CRT version to 9.0.30729.4148. This version is referenced in "c:\Program Files\Microsoft Visual Studio 9.0\VC\redist\x86\Microsoft.VC90.CRT\Microsoft.VC90.CRT.manifest"

So we have build our hello application with version 9.0.30729.1 and we distribute the CRT with version 9.0.30729.4148, which of course doesn't work in practice.

Others have encountered this problem and they have taken drastic measures like reinstallation of Visual Studio 2008 and/or manually change the CRT version in "c:\Program Files\Microsoft Visual Studio 9.0\VC\include\crtassem.h" header file.

Since these manifest files are xml files why not just change them using the manifest tool?

The following two commands extract and repack the RT_MANIFEST resource:
mt.exe -inputresource:hello.exe;#1 -out:hello.manifest
mt.exe -outputresource:hello.exe;#1 -manifest hello.manifest

Now there is the issue of replacing "9.0.30729.1" to "9.0.30729.4148" in hello.manifest and since sed is not present on a normal Windows machine I have created a Javascript script which does this task, which is called like this:

cscript.exe replace_string.js hello.manifest "9.0.30729.1" "9.0.30729.4148"

This way we can update the CRT files without having to wait for Visual Studio to catch up.

They say Visual Studio 2010 has addressed the whole manifest nightmare and one can copy the CRT files alongside the executable file without any hacking.

2009-09-30

Batch change script for Visual C/C++ Projects

Visual C/C++ projects are XML files but they have a different file extension (*.vcproj).

Having to change an option to through tens of projects files each with more than one platform (Win32, Win64, Windows Mobile) and multiple configurations (Debug, Release) only by loading the projects in Visual Studio and clicking through the UI is not very appealing.

Since we already know that the project files are XML files one can write a program / script to change the desired option, in my case the change of the C runtime library - dynamic / static.

I have chosen WSH JScript, MSXML 3.0 and XPath to write a script to change Visual C/C++ projects. My decision was due two arguments: JScript is present on Windows XP, and the scripts can be debugged by Visual Studio 2005+ (//X command line parameter).

During the development I have stumbled on a XPath query problem, the function contains was not found in msxml3.dll. The problem was due to the fact that MSXML 3.0 was not instructed to use XPath as selection language (xmlDoc.setProperty("SelectionLanguage", "XPath");). Newer MSXML versions do not have this requirement though.

The message boxes displayed when issued from command line like change_runtime.js myproject.vcproj are due to the fact that JScript is not the default scripting language in WSH. One solution is to call the script like: cscript change_runtime.js myproject.vcproj, which requires some typing, the other solution is to change the default scripting language in WSH, which can be accomplished by running cscript //H:CScript.

The source code can be found here. Changing Visual C/C++ projects just become easier for me :-)

2009-05-12

Visual Studio 2008 Donation

I would like to thank Opera Software for the retail package of Visual Studio 2008 Standard Edition I just received!


Thank you!

2008-06-10

Why Microsoft? Why?!

I haven't mentioned here that I lost my fate in Microsoft that they can deliver good development tools a long time ago, I guess that was when I saw Visual Studio .NET 2002 for the first time. The .NET age fuc*ed it up real good.

At work I have Visual Studio 2003 and 2005 installed on D drive. Now I had to install Visual Studio 2008 on my system. I choose D drive, I verify every component that it should install on D drive and click Next, Next... Finish.

To my surprise the C++ component (VC directory) was installed on C drive, I said to myself... hmm, maybe I've forgot to install it on D, but it was working and I've ignored the issue.

The problem was when I've tried to compile something from the console. I've opened a console, setup the environment variables "c:\Program Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat" and then hit nmake.

It complained that it could not find rc.exe, WTF. Then I found out that rc.exe is part of the Microsoft SDK which was on D (D:\Program Files\Microsoft SDKs\Windows\v6.1\Bin\). When I try to setup the environment variables for Microsoft SDK ("d:\Program Files\Microsoft SDKs\Windows\v6.1\Bin\SetEnv.Cmd" ) it complains that it can not find a compiler...

So now I'm installing everything on C drive, because for Microsoft, C++ should stay on C drive.

Edit: It works now (everything is on drive D), I've uninstalled all the programs that had a connection with Visual Studio 2008. If at first you don't succeed then try again, and again, and again.