Showing posts with label Visual Studio. Show all posts
Showing posts with label Visual Studio. Show all posts

Thursday, 27 June 2013

Beginning Unit Testing with NUnit in Visual Studio

How to start with NUnit?

Download it from http://www.nunit.org/ and install it. It should be installed at C:\Program Files (x86)\NUnit 2.6.2. (2.6.2 is the current release version in the time of writing this article)

How to organise my projects? Where to put unit tests?

Put the business logic of your app in a class library project (e.g. MyBusinessLogic.dll). Your main app (MyApp.exe) project references this dll. Put unit tests in a separate project (e.g. MyBusinessLogicTester.dll) but within the same solution. MyBusinessLogicTester.dll will reference nunit.framework.dll (located at C:\Program Files (x86)\NUnit 2.6.2\bin) and MyBusinessLogic.dll.

How to run NUnit tests?

In MyBusinessLogicTester project: go to Properties -> Debug. Set Start external program to C:\Program Files (x86)\NUnit 2.6.2\bin\nunit.exe and put MyBusinessLogicTester.dll in Command line arguments field.

Set MyBusinessLogicTester as a StartUp project in your solution and run it. Nunit GUI app (nunit.exe) will open and display all test fixtures and tests in the left-hand side tree view. You can select tests you want to run and then execute them.

If you're running MyBusinessLogicTester tests with ReSharper, make sure MyBusinessLogicTester is marked to be built in the Configuration Manager.


Links and References:
http://www.nunit.org/
http://stackoverflow.com/questions/67299/is-unit-testing-worth-the-effort
http://stackoverflow.com/questions/1365943/how-to-start-unit-testing-or-tdd
http://stackoverflow.com/questions/347156/do-you-put-unit-tests-in-same-project-or-another-project
http://stackoverflow.com/questions/3979855/how-do-i-set-up-nunit-to-run-my-projects-unit-tests
http://stackoverflow.com/questions/759854/how-do-i-run-nunit-in-debug-mode-from-visual-studio
http://stackoverflow.com/questions/3476054/can-unit-testing-be-successfully-added-into-an-existing-production-project-if-s
http://stackoverflow.com/questions/6103807/unit-testing-philosophy


Wednesday, 15 February 2012

Static code analysis

One simple way of improving your code is passing it through some of static code analysis tools and fix reported errors and warnings. Such tools will usually point out lines in code that could possibly cause issues with buffer overruns, uninitialized memory, null pointer dereferences, memory and resource leaks, exception safety...or lines that contain code which style could be improved.

If you are using Visual Studio 2010, you can use its static code analysis: open Project Properties -> Configuartion Properties -> Code Analysis. Select desired build configuration and platform and tick Enable Code Analysis for C/C++ on Build. Output window will show code analysis report (search for Running Code Analysis for C/C++... lines).

I want to show here how it looks in the practice. Let's say we have some smelly code:

C.h:

#ifndef _C_H_
#define _C_H_

class C
{
   // unitialized member
   int m_n;
public:
   C()
   {  
      // unused variable
      int j;
   }

   void Init(char ch)
   {
      // C-style pointer cast
      m_n = (int)ch;
   }
};
#endif // _C_H_


main.cpp:

#include "C.h"

// unused function
int foo()
{
   int n;
   return 0;
}

int main()
{
   // unused variable
   int n1; 

   // dereferencing unitialized pointer
   int* pInt1;
   *pInt1 = 1;

   // dereferencing NULL pointer
   int* pInt2 = 0;
   *pInt2 = 2;

   // memory leak - no delete
   int* pInt3 = new int(2);

   // scope of n2 is unecessarily main()
   int n2 = 0;

   {
      char ch = 2;
      n2 = (int)ch;
   }

   int arr[2];
   arr[2] = 3;

   return 0;
}


I played recently with Cppcheck and this is what it reports for the code above:

Cppcheck-report

Visual Studio prints code analysis messages in the Output window and for the code above it contains the following:

1>------ Build started: Project: CppcheckTest, Configuration: Debug Win32 ------
1>Build started 15/02/2012 19:49:12.
1>InitializeBuildStatus:
1> Touching "Debug\CppcheckTest.unsuccessfulbuild".
1>ClCompile:
1> main.cpp
1>c:\...\cppchecktest\c.h(12): warning C4101: 'j' : unreferenced local variable
1>c:\...\cppchecktest\main.cpp(6): warning C4101: 'n' : unreferenced local variable
1>c:\...\cppchecktest\main.cpp(13): warning C4101: 'n1' : unreferenced local variable
1>c:\...\cppchecktest\main.cpp(35): warning C6201: Index '2' is out of valid index range '0' to '1' for possibly stack allocated buffer 'arr'
1>c:\...\cppchecktest\main.cpp(17): warning C6001: Using uninitialized memory 'pInt1': Lines: 13, 16, 17
1>c:\...\cppchecktest\main.cpp(21): warning C6011: Dereferencing NULL pointer 'pInt2': Lines: 13, 16, 17, 20, 21
1>c:\...\cppchecktest\main.cpp(35): warning C6386: Buffer overrun: accessing 'arr', the writable size is '8' bytes, but '12' bytes might be written: Lines: 13, 16, 17, 20, 21, 24, 27, 30, 31, 34, 35
1>c:\...\cppchecktest\main.cpp(17): warning C4700: uninitialized local variable 'pInt1' used
1>ManifestResourceCompile:
1> All outputs are up-to-date.
1>Manifest:
1> All outputs are up-to-date.
1>LinkEmbedManifest:
1> All outputs are up-to-date.
1> CppcheckTest.vcxproj -> C:\...\CppcheckTest\Debug\CppcheckTest.exe
1>FinalizeBuildStatus:
1> Deleting file "Debug\CppcheckTest.unsuccessfulbuild".
1> Touching "Debug\CppcheckTest.lastbuildstate".
1>
1>Build succeeded.
1>
1>Time Elapsed 00:00:04.38
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========


Links and References:
Analyzing Application Quality by Using Code Analysis Tools (MSDN)
How to: Enable and Disable Automatic Code Analysis for C/C++ (MSDN)
Cppcheck

Thursday, 27 October 2011

How to include stdafx.h conditionally?

Don't try it as that's not possible!

If you try to put #include "stdafx.h" between #ifdef and #endif, you'll end up with error C1020: unexpected #endif. You need to include stdafx.h at the beginning of any source file in your project, apart from those files for which using precompiled headers is turned off.

There is one situation where this feature - setting using precompiled headers at the file level - comes very handy. Let's say we have some code file which does not include stdafx.h and we need to share it between project which uses precompiled headers - P1, and project which doesn't - P2. If we add that file to P1, this project won't compile  - compiler will complain with fatal error C1010: unexpected end of file while looking for precompiled header. We cannot include stdafx.h at the beginning of that file either as then P2 won't compile - it does not have stdafx.h. The only solution is to turn off using precompiled headers for that particular file.

Friday, 7 October 2011

Conditional compilation of resource file in Visual Studio

How to use different resources in different build configurations, having a single resource file in project? 
Answer: define different resource file preprocessor symbols for different configurations.


1. Open your project in Visual Studio 2008

2. Right click on resource script file (e.g. app.rc) and select "Properties"


3. At the top of the property page, select one platform like "Win32" or "x64".

4. In the left menu bar, select [Configuration Properties] / [Resources] / [General].

5. In the "Preprocessor Definitions" field, add "WIN32" for "Win32" platform and "WIN64" for "x64" platform. The field value will become "WINXX;_UNICODE;UNICODE". (XX will be 32 or 64)


6. Click OK to close the window.


7. Right click on resource script file (e.g. app.rc) and select "View Code".


8. In the code editor, add #ifdef and #elif to conditionally include resources when compiling. Use "WIN32" and "WIN64" preprocessor definitions that we defined just now. 



Here is a sample code:
--------------------------------
#ifdef WIN32
   IDB_BITMAP1             BITMAP                  "bitmap1.bmp"
   IDB_BITMAP2             BITMAP                  "bitmap2.bmp"
#elif WIN64
   IDR_TOOLBAR1         BITMAP                   "toolbar1.bmp"
   IDI_ICON1                  ICON                       "icon1.ico"
#endif
--------------------------------

9. Save the resource script file and compile the project in different platforms.


[source]

Thursday, 6 October 2011

32-bit and 64-bit versions of Windows C++ application

How to set compiler and linker options in order to build some C++ application for 64-bit Windows? Sample application I will test this on is one that detects two things that should not be mixed:
  • detecting which processor architecture application has been compiled for (performed in compile time)
  • detecting which processor architecture application is running on (performed in run-time)
There is no portable way of performing these checks.

Compiler's target architecture can be detected by checking which pre-defined symbols (macros) have automatically been defined by compiler (this is compiler specific! - different compilers use different macros). Some Microsoft-specific are:

_WIN32 - defined for applications for Win32 and Win64. Always defined.
_WIN64 - defined for applications for Win64.
_M_AMD64 - defined for x64 processors
_M_X64 - defined for x64 processors
_M_IX86 - defined for x86 processors
_M_IA64 - defined for Itanium Processor Family 64-bit processors

These macros determine target processor - one that we are building application for (not processor we are building on). We don't need to add them manually as compiler will define them: _WIN32 and _M_IX86 for 32-bit applications and _WIN64, _M_AMD64, _M_X64 and _M_IA64 for 64-bit ones.

Another test can be checking the value of the sizeof(void*). It is 4 bytes in applications compiled for 32-bit architectures and 8 bytes in 64-bit applications, regardless on the processor architecture application is running on.

Host's processor architecture can be obtained in run-time in various ways, of which some of them (on Windows) are:
  •  __cpuid
  • check PROCESSOR_ARCHITECTURE and PROCESSOR_ARCHITEW6432 environment variables (or read value of PROCESSOR_ARCHITECTURE in registry on path HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment)
  • Use GetSystemInfo() or GetNativeSystemInfo()
main.cpp uses methods described above:

#include <windows.h>
#include <iostream>
#include <string>
#include <intrin.h>
using namespace std;

void CheckIs64BitAvailable()
{
bool b64Available = false;
int CPUInfo[4] = {0};
        __cpuid(CPUInfo, 0);
        b64Available = (CPUInfo[3] & 0x20000000) || false;

if(b64Available)
{
cout << "64-bit processor" << endl;
}
else
{
cout << "32-bit processor" << endl;
}
}

void CheckNativeSystemProcessorArchitecture()
{
SYSTEM_INFO si;
memset(&si, 0, sizeof(si));
GetNativeSystemInfo(&si);

switch(si.wProcessorArchitecture)
{
case PROCESSOR_ARCHITECTURE_AMD64:
cout << "PROCESSOR_ARCHITECTURE_AMD64 - x64 (AMD or Intel)" << endl;
break;
case PROCESSOR_ARCHITECTURE_IA64:
cout << "PROCESSOR_ARCHITECTURE_IA64 - Intel Itanium-based" << endl;
break;
case PROCESSOR_ARCHITECTURE_INTEL:
cout << "PROCESSOR_ARCHITECTURE_INTEL - x86" << endl;
break;
case PROCESSOR_ARCHITECTURE_UNKNOWN:
cout << "PROCESSOR_ARCHITECTURE_UNKNOWN - Unknown architecture" << endl;
break;
}
}

void CheckSystemProcessorArchitecture()
{
cout << "Calling GetSystemInfo()..." << endl;

SYSTEM_INFO si;
memset(&si, 0, sizeof(si));
GetSystemInfo(&si);

switch(si.wProcessorArchitecture)
{
case PROCESSOR_ARCHITECTURE_AMD64:
cout << "PROCESSOR_ARCHITECTURE_AMD64 - x64 (AMD or Intel)" << endl;
break;
case PROCESSOR_ARCHITECTURE_IA64:
cout << "PROCESSOR_ARCHITECTURE_IA64 - Intel Itanium-based" << endl;
break;
case PROCESSOR_ARCHITECTURE_INTEL:
cout << "PROCESSOR_ARCHITECTURE_INTEL - x86" << endl;
break;
case PROCESSOR_ARCHITECTURE_UNKNOWN:
cout << "PROCESSOR_ARCHITECTURE_UNKNOWN - Unknown architecture" << endl;
break;
}
}

void CheckEnvVariable_PROCESSOR_ARCHITECTURE()
{
char* pszProcArch = getenv("PROCESSOR_ARCHITECTURE");
if(pszProcArch)
{
cout << "PROCESSOR_ARCHITECTURE (environment variable): " << string(pszProcArch) << endl;
}
else
{
cout << "PROCESSOR_ARCHITECTURE (environment variable) not found" << endl;
}
}

void CheckEnvVariable_PROCESSOR_ARCHITEW6432()
{
// PROCESSOR_ARCHITEW6432 is defined only in WoW64 where reports the original native processor architecture
char* pszProcArch = getenv("PROCESSOR_ARCHITEW6432");
if(pszProcArch)
{
cout << "PROCESSOR_ARCHITEW6432 (environment variable): " << string(pszProcArch) << endl;
}
else
{
cout << "PROCESSOR_ARCHITEW6432 (environment variable) not found" << endl;
}
}

void CheckRegVal_PROCESSOR_ARCHITECTURE()
{
HKEY hKey;
DWORD dwBuffSize = 1023;
DWORD dwType;
char szValue[1024] = {0};

LONG lErrorCode = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment",
0,
KEY_QUERY_VALUE,
&hKey);

if(lErrorCode!= ERROR_SUCCESS)
{
cout << "RegOpenKeyEx() failed. Error: " << lErrorCode << endl;
return;
}
 
RegQueryValueEx(
hKey,
"PROCESSOR_ARCHITECTURE",
NULL,
&dwType,
(LPBYTE)szValue,
&dwBuffSize);

cout << "PROCESSOR_ARCHITECTURE (registry value): " << string(szValue) << endl;

RegCloseKey(hKey);        
}

int main()
{
cout << "sizeof(void*) = " << sizeof(void*) << " [bytes]"<< endl;

CheckIs64BitAvailable();
CheckRegVal_PROCESSOR_ARCHITECTURE();

// Defined for applications for Win32 and Win64. Always defined.
#ifdef _WIN32
cout << "_WIN32 defined" << endl;
#endif

// _WIN64 is defined for applications for Win64 (they can run only on Win64)
#ifdef _WIN64
cout << "_WIN64 defined => target architecture is Win64; Process is running on native Win64" << endl;
CheckSystemProcessorArchitecture();
CheckEnvVariable_PROCESSOR_ARCHITECTURE();
#else
cout << "_WIN64 is not defined => target architecture is Win32" << endl;

BOOL bIs64 = FALSE;
IsWow64Process(GetCurrentProcess(), &bIs64);

if(bIs64)
{
cout << "Process is running under WoW64" << endl;
CheckNativeSystemProcessorArchitecture();
CheckEnvVariable_PROCESSOR_ARCHITEW6432();
}
else
{
cout << "Process is running on Win32" << endl;
CheckSystemProcessorArchitecture();
CheckEnvVariable_PROCESSOR_ARCHITECTURE();
}
#endif

// WIN32 is defined outside compiler - by the SDK or the build environment
#ifdef WIN32
cout << "WIN32 defined" << endl;
#endif

// WIN64 is defined outside compiler - by the SDK or the build environment
#ifdef WIN64
cout << "WIN64 defined" << endl;
#endif

// Pre-defined Architecture Macro: Intel x86; Defined for x86 processors
#ifdef _M_IX86
cout << "_M_IX86 defined: " << _M_IX86 << endl;
#endif

// Pre-defined Architecture Macro: AMD64; Defined for x64 processors.
#ifdef _M_X64
cout << "_M_X64 defined: " << _M_X64 << endl;
#endif

// Defined for x64 processors.
#ifdef _M_AMD64
cout << "_M_AMD64 defined: " << _M_AMD64 << endl;
#endif

// Pre-defined Architecture Macro: Intel Architecture-64 (Defined for Itanium Processor Family 64-bit processors.)
#ifdef _M_IA64
cout << "_M_IA64 defined: " << _M_IA64 << endl;
#endif

return 0;
}

This is application's output when run on 32-bit Windows (Win 7):
..\Release>ProcArchTest_x86.exe
sizeof(void*) = 4 [bytes]
32-bit processor
PROCESSOR_ARCHITECTURE (registry value): x86
_WIN32 defined
_WIN64 is not defined => target architecture is Win32
Process is running on Win32
Calling GetSystemInfo()...
PROCESSOR_ARCHITECTURE_INTEL - x86
PROCESSOR_ARCHITECTURE (environment variable): x86
WIN32 defined
_M_IX86 defined: 600

C:\DEVELOPMENT\RESEARCH\C++\ProcessorBitTest\Release>

This is application's output when run on 64-bit Windows (Win 7 emulated on VirtualBox):
C:\Users\Bojan\Desktop>ProcArchTest_x86.exe
sizeof(void*) = 4 [bytes]
32-bit processor
PROCESSOR_ARCHITECTURE (registry value): AMD64
_WIN32 defined
_WIN64 is not defined => target architecture is Win32
Process is running under WoW64
PROCESSOR_ARCHITECTURE_AMD64 - x64 (AMD or Intel)
PROCESSOR_ARCHITEW6432 (environment variable): AMD64
WIN32 defined
_M_IX86 defined: 600

C:\Users\Bojan\Desktop>

Now, let us build this application for 64-bit Windows. In Visual Studio, we need to create a new build platform: Build -> Configuration Manager -> Active Solution Platform, New; select "x64" and copy settings from Win32.

Let us compare compiler options for 32-bit and 64-bit Release configurations in order to see what are the differences:

Compiler options for Win32 Release:
/Zi /nologo /W3 /WX- /O2 /Oi /Oy- /GL /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /Gm- /EHsc /MT /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Fp"Release\ProcArchTest_x86.pch" /Fa"Release\" /Fo"Release\" /Fd"Release\vc100.pdb" /Gd /analyze- /errorReport:queue

Compiler options for x64 Release:
/Zi /nologo /W3 /WX- /O2 /Oi /GL /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /Gm- /EHsc /MT /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Fp"x64\Release\ProcArchTest_x64.pch" /Fa"x64\Release\" /Fo"x64\Release\" /Fd"x64\Release\vc100.pdb" /Gd /errorReport:queue

We can see that all options are the same except in case of /Oy and /analyze which are available only for x86 compilers.

What about linker options?

Linker options for Win32 Release:
/OUT:"..\Release\ProcArchTest_x86.exe" /INCREMENTAL:NO /NOLOGO "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /MANIFEST /ManifestFile:"Release\ProcArchTest_x86.exe.intermediate.manifest" /ALLOWISOLATION /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"..\ProcessorBitTest\Release\ProcArchTest_x86.pdb" /SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF /PGD:"..\ProcessorBitTest\Release\ProcArchTest_x86.pgd" /LTCG /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86 /ERRORREPORT:QUEUE

Linker options for x64 Release:
/OUT:"..\x64\Release\ProcArchTest_x64.exe" /INCREMENTAL:NO /NOLOGO "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /MANIFEST /ManifestFile:"x64\Release\ProcArchTest_x64.exe.intermediate.manifest" /ALLOWISOLATION /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"..\ProcessorBitTest\x64\Release\ProcArchTest_x64.pdb" /SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF /PGD:"..\ProcessorBitTest\x64\Release\ProcArchTest_x64.pgd" /LTCG /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X64 /ERRORREPORT:QUEUE

We can see that linker options differ only in the value of /MACHINE option.

NOTE: /MACHINE option does not need to be set at all! Compiler inserts information about target architecture in OBJ files' headers. OBJ files created with Microsoft compiler have PE/COFF format which is described in Microsoft PE and COFF Specification. At the beginning of an object file, or immediately after the signature of an image file, is a standard COFF file header. Its first field is "Machine" whose value is the number that identifies the type of target machine (CPU type). Some values are: IMAGE_FILE_MACHINE_AMD64 (x64), IMAGE_FILE_MACHINE_I386 (Intel 386 or later processors and compatible processors - x86), IMAGE_FILE_MACHINE_IA64 (Intel Itanium processor family). Linker reads that information. If you compile your app with $(VCInstallDir)bin\x86_amd64\cl.exe linker will create amd64 binary even with /MACHINE Not Set! Cross-compiling with Microsoft (Visual Studio) tools is all about using correct compiler and linker! Compiler and linker options can actually be same for both 32-bit and 64-bit builds! When building 64-bit application in Visual Studio, just make sure that Executable Directories has (cl.exe and link.exe) paths in this order $(VCInstallDir)bin\x86_amd64;$(VCInstallDir)bin; and that AMD paths are listed first in Include and Library Directories (but all this should be done automatically upon creation of x64 project!).

Let us continue with analysis.

Although names of some libraries end with "32" for both x86 and x64 configurations, their different (32-bit or 64-bit) versions are actually used in different builds. Same for the compiler and linker - please read my article "NMAKE and its environment".

Let us try to run now our 64-bit application on 32-bit Windows OS:
..\x64\Release>ProcArchTest_x64.exe
This version of ..\x64\Release\ProcArchTest_x64.exe is not compatible with the
version of Windows you're running. Check your computer's system information
to see whether you need a x86 (32-bit) or x64 (64-bit) version of the program,
and then contact the software publisher.

C:\DEVELOPMENT\RESEARCH\C++\ProcessorBitTest\x64\Release>

This was expected as 64-bit application cannot run on 32-bit operating systems.
What about running it in its natural, 64-bit, enviroment - on 64-bit OS?

C:\Users\Bojan\Desktop>ProcArchTest_x64.exe
sizeof(void*) = 8 [bytes]
32-bit processor
PROCESSOR_ARCHITECTURE (registry value): AMD64
_WIN32 defined
_WIN64 defined => target architecture is Win64; Process is running on native Win
64
Calling GetSystemInfo()...
PROCESSOR_ARCHITECTURE_AMD64 - x64 (AMD or Intel)
PROCESSOR_ARCHITECTURE (environment variable): AMD64
WIN32 defined
_M_X64 defined: 100
_M_AMD64 defined: 100

C:\Users\Bojan\Desktop>

Conclusion:
  • application targets 64-bit architecture if _WIN64, _M_X64 and/or _M_AMD64 are defined and/or if sizeof(void*) is 8
  • reliable way of getting the architecture of the host processor in runtime is reading PROCESSOR_ARCHITECTURE value from registry or using GetSystemInfo()/GetNativeSystemInfo()
Advice:
Don't rely on WoW64 as it might not be enabled/installed on the target machine (e.g. WoW64 is optional on Windows Server 2003 R2). WoW64 is intended to support legacy 32-bit applications anyway. Build new applications for both x86 and x64 architectures. This way you can avoid some potential errors in applications that can occur due to directory and registry redirections under WoW64.

Links and references:

IsWow64Process function
64-bit (Wikipedia)
WoW64 (Wikipedia)
Use Visual Studio to build 64-bit application (MSDN blog)
Everything You Need To Know To Start Programming 64-Bit Windows Systems
Visual Studio Development Environment 64-Bit Support
HOWTO: Detect Process BitnessHow to: Configure Projects to Target Platforms (MSDN)
How to: Configure Visual C++ Projects to Target 64-Bit Platforms (MSDN)
How to determine whether a computer is running a 32-bit version or 64-bit version of the Windows operating system (MSDN)
Predefined Macros (MSDN)
You already know what your target architecture is (or at least you should)
How to detect programmatically whether you are running on 64-bit Windows
Detecting CPU architecture compile-time
Detect system architecture (x86/x64) while running
#ifdef for 32-bit platform
Determining 64-bit vs. 32-bit Windows
Use Visual Studio to build 64-bit application
Seven Steps of Migrating a Program to a 64-bit System

Monday, 3 October 2011

NMAKE and its environment

nmake is a Microsoft's command-line tool for building C/C++ applications. nmake comes with Visual Studio and Windows Driver Development Kit (DDK) and it comes in two versions: one for building 32-bit and another for building 64-bit binaries. Here is the list of its locations, depending on which Microsoft product is installed on your machine:

Visual Studio 2010:
C:\Program Files\Microsoft Visual Studio 10.0\VC\bin\nmake.exe
(32-bit binary; depends on 32-bit advapi32.dll, kernel32.dll and msvcr100.dll)

C:\Program Files\Microsoft Visual Studio 10.0\VC\bin\amd64\nmake.exe
(64-bit binary; depends on 64-bit advapi32.dll, kernel32.dll and msvcr100.dll)

Visual Studio 2008:
C:\Program Files\Microsoft Visual Studio 9.0\VC\bin\nmake.exe
(32-bit binary; depends on 32-bit advapi32.dll, kernel32.dll and msvcr90.dll)

C:\Program Files\Microsoft Visual Studio 9.0\VC\bin\amd64\nmake.exe
(64-bit binary; depends on 64-bit advapi32.dll, kernel32.dll and msvcr90.dll)

Windows DDK (I have some pretty old installed on my machine):
C:\WinDDK\6001.18001\bin\x86\nmake.exe
(32-bit binary; depends on 32-bit advapi32.dll, kernel32.dll and msvcr80.dll)

C:\WinDDK\6001.18001\bin\ia64\nmake.exe
(64-bit binary; depends on 64-bit advapi32.dll, kernel32.dll and msvcr80.dll)

Binaries from amd64/ia64 directories are 64-bit and cannot be run on 32-bit machines.

msvcrXX.dll is Microsoft Visual C Runtime library. XX is its version, specific for each version of Visual Studio: 80 for VS2005, 90 for VS2008 and 100 for VS2010. Binary linked against some msvcr library requires existence of that library on the machine it runs on. If it does not exist, it can be installed with Microsoft Visual C++ VS20XX Redistributable Package (x86 or x64).

If you want to run some particular nmake on your machine, make sure its path is listed in Paths environment variable. If there are more versions of nmake present on your machine, put path to desired version before paths to the other versions. E.g. put path "C:\Program Files\Microsoft Visual Studio 10.0\VC\bin" before "C:\Program Files\Microsoft Visual Studio 9.0\VC\bin" in Paths if you want to run VS2010 nmake. You can always check which nmake will be called from some arbitrary location if executing (from a command line):

where nmake

If nmake resides in multiple directories, all those directories will be listed but only instance from the first listed will be called,
nmake reads instructions from a file called makefile (full name of this file usually does not contain a dot and extension). Instructions of how to build a specific binary (or binaries) are grouped into named targets. Those instructions contain compiler and linker calls, provided with source files, paths to headers, dependencies, object file names and compiler and linker options. Tags for groups of targets or sets of instructions that don't make binaries (like creating or deleting files or directories) are pseudo-targets.

You need to provide target or pseudo-target name when calling nmake. You can provide path to makefile; without it nmake looks for it in the current directory.

makefile contains instruction to call Microsoft compiler, cl.exe and linker, link.exe. Just like nmake, they come with Visual Studio and Windows DDK.

Visual Studio 2010:
c:\Program Files\Microsoft Visual Studio 10.0\VC\bin\amd64\cl.exe
c:\Program Files\Microsoft Visual Studio 10.0\VC\bin\amd64\link.exe
(64-bit compiler and linker for AMD64 architecture)

c:\Program Files\Microsoft Visual Studio 10.0\VC\bin\cl.exe
c:\Program Files\Microsoft Visual Studio 10.0\VC\bin\link.exe
(32-bit compiler and linker for building 32-bit applications)

c:\Program Files\Microsoft Visual Studio 10.0\VC\bin\x86_amd64\cl.exe
(depends on advapi32.dll, kernel32.dll, msvcr100.dll, version.dll, psapi.dll and shell32.dll from C:\Windows\System32 and mspdb100.dll from c:\program files\microsoft visual studio 10.0\common7\ide)

c:\Program Files\Microsoft Visual Studio 10.0\VC\bin\x86_amd64\link.exe
(depends on advapi32.dll, kernel32.dll, msvcr100.dll, psapi.dll and user32.dll from C:\Windows\System32 and mspdb100.dll from c:\program files\microsoft visual studio 10.0\common7\ide) (32-bit cross-compiler and linker for building 64-bit applications for AMD64 architectures)

c:\Program Files\Microsoft Visual Studio 10.0\VC\bin\x86_ia64\cl.exe
c:\Program Files\Microsoft Visual Studio 10.0\VC\bin\x86_ia64\link.exe
(32-bit cross-compiler and linker for building 64-bit applications for Itanium architectures)

Visual Studio 2008:
c:\Program Files\Microsoft Visual Studio 9.0\VC\bin\amd64\cl.exe
c:\Program Files\Microsoft Visual Studio 9.0\VC\bin\amd64\link.exe

c:\Program Files\Microsoft Visual Studio 9.0\VC\bin\cl.exe
c:\Program Files\Microsoft Visual Studio 9.0\VC\bin\link.exe

c:\Program Files\Microsoft Visual Studio 9.0\VC\bin\x86_amd64\cl.exe
c:\Program Files\Microsoft Visual Studio 9.0\VC\bin\x86_amd64\link.exe

c:\Program Files\Microsoft Visual Studio 9.0\VC\ce\bin\x86_arm\cl.exe
c:\Program Files\Microsoft Visual Studio 9.0\VC\ce\bin\x86_arm\link.exe

c:\Program Files\Microsoft Visual Studio 9.0\VC\ce\bin\x86_mips\cl.exe
c:\Program Files\Microsoft Visual Studio 9.0\VC\ce\bin\x86_mips\link.exe

c:\Program Files\Microsoft Visual Studio 9.0\VC\ce\bin\x86_sh\cl.exe
c:\Program Files\Microsoft Visual Studio 9.0\VC\ce\bin\x86_sh\link.exe

Windows DDK:
c:\WinDDK\6001.18001\bin\ia64\ia64\cl.exe
c:\WinDDK\6001.18001\bin\ia64\ia64\link.exe
c:\WinDDK\6001.18001\bin\x86\amd64\cl.exe
c:\WinDDK\6001.18001\bin\x86\amd64\link.exe
c:\WinDDK\6001.18001\bin\x86\ia64\cl.exe
c:\WinDDK\6001.18001\bin\x86\ia64\link.exe
c:\WinDDK\6001.18001\bin\x86\x86\cl.exe
c:\WinDDK\6001.18001\bin\x86\x86\link.exe

Again, which compiler and linker will be called depends on paths listed in Path environment variable. Paths used can be checked by calling (from a command line):

where cl.exe
where link.exe

For example, if we want to build some 64-bit application for AMD architecture (which is usually named x64 and is more common than Itanium one) and we we want to build it on 32-bit machine, using VS2010, we need to use cross-compiler and so will add following paths to Path environment variable:
C:\Windows\System32; (path to dlls used by cl.exe and link.exe)
c:\program files\microsoft visual studio 10.0\common7\ide; (path to dlls used by cl.exe and link.exe)
C:\Program Files\Microsoft Visual Studio 10.0\VC\bin\x86_amd64; (path to cl.exe and link.exe)
C:\Program Files\Microsoft Visual Studio 10.0\VC\bin; (path to nmake.exe)

If you try to run 64-bit compiler on 32-bit machine, you'll get message:
c:\Program Files\Microsoft Visual Studio 10.0\VC\bin\amd64>cl.exe /?
This version of c:\Program Files\Microsoft Visual Studio 10.0\VC\bin\amd64\cl.ex
e is not compatible with the version of Windows you're running. Check your compu
ter's system information to see whether you need a x86 (32-bit) or x64 (64-bit)
version of the program, and then contact the software publisher.

You can run 32-bit compiler or 32-bit cross-compiler on 32-bit machine only:
c:\Program Files\Microsoft Visual Studio 10.0\VC\bin\x86_amd64>cl.exe /?
Microsoft (R) C/C++ Optimizing Compiler Version 16.00.30319.01 for x64
Copyright (C) Microsoft Corporation. All rights reserved.

This is not enough for nmake build to be successful. Compiler reads paths to Visual C++ and Windows SDK (Windows Framework) headers from INCLUDE environment variable. These headers are coming with each version of Visual Studio and we need to make sure cl.exe will be using correct ones. For example, if we want to use VS2010, we will set INCLUDE as:
c:\Program Files\Microsoft Visual Studio 10.0\VC\include; (Visual C++ headers - part of Microsoft's implementation of C++ standard)
c:\Program Files\Microsoft Visual Studio 10.0\VC\atlmfc\include; (ATL/MFC headers - add this path only for this type of applications)
c:\Program Files\Microsoft SDKs\Windows\v7.0A\include; (Windows SDK headers)

Furthermore, linker reads paths to Visual C++ and Windows Framework libraries from LIB environment variable. These libraries are specific for each version of Visual Studio and target architecture. If using VS2010 and building binary for AMD64 architecture, we would set LIB as:
c:\Program Files\Microsoft Visual Studio 10.0\VC\lib\amd64; (Visual C++ libraries)
c:\Program Files\Microsoft Visual Studio 10.0\VC\atlmfc\lib\amd64; (ATL/MFC libraries- add this path only for this type of applications)
c:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\x64; (Windows SDK libraries)

Of course, if your application depends on some other framework or package, INCLUDE needs to contain path to its headers and LIB path to its libraries.

I wrote one short batch file for setting Visual Studio environment (environmental variables) for x86 or x64 builds:
setenv.bat (caret character is used to break long lines):
@rem B.Komazec Setting environment for using Microsoft Visual Studio 2010 x86/x64 tools.
@echo off

@if "%1"=="x86" goto set_x86
@if "%1"=="x64" goto set_x64
@if "%1"=="" goto error

:set_x86
@echo Setting environment for using Microsoft Visual Studio 2010 x86 tools.

set INCLUDE=^
c:\Program Files\Microsoft Visual Studio 10.0\VC\include;^
c:\Program Files\Microsoft SDKs\Windows\v7.0A\include;

set LIB=^
c:\Program Files\Microsoft Visual Studio 10.0\VC\lib;^
c:\Program Files\Microsoft SDKs\Windows\v7.0A\lib;

set PATH=^
%SystemRoot%\system32;^
c:\Program Files\Microsoft Visual Studio 10.0\VC\bin;^
c:\program files\microsoft visual studio 10.0\common7\ide;

goto test_bin_locations

:set_x64
@echo Setting environment for using Microsoft Visual Studio 2010 x64 tools.

set INCLUDE=^
c:\Program Files\Microsoft Visual Studio 10.0\VC\include;^
c:\Program Files\Microsoft SDKs\Windows\v7.0A\include;

set LIB=^
c:\Program Files\Microsoft Visual Studio 10.0\VC\lib\amd64;^
c:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\x64;

set PATH=^
%SystemRoot%\system32;^
C:\Program Files\Microsoft Visual Studio 10.0\VC\bin\x86_amd64;^
C:\Program Files\Microsoft Visual Studio 10.0\VC\bin;^
C:\Program Files\Microsoft Visual Studio 10.0\Common7\ide;

goto test_bin_locations

:test_bin_locations
@echo on
where nmake
where cl.exe
where link.exe
@echo off
goto:eof

:error
@echo Usage: setenv.bat [x86^|x64]

goto:eof

For example, to set environment for building x64 (AMD64) application with VS2010, call this script providing "x64" as an argument:

setenv x64

Note that changes made with SET will remain only for the duration of the current CMD session. To check the value of some environment variable in command prompt window use ECHO command followed by environment variable surrounded with percent signs:

echo %Path%

You can also use batch files that come with Visual Studio:
Visual Studio 2010:
C:\Program Files\Microsoft Visual Studio 10.0\VC\bin\vcvars32.bat
C:\Program Files\Microsoft Visual Studio 10.0\VC\bin\x86_amd64\vcvarsx86_amd64.bat
C:\Program Files\Microsoft Visual Studio 10.0\VC\bin\x86_ia64\vcvarsx86_ia64.bat
C:\Program Files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat

Visual Studio 2008:
C:\Program Files\Microsoft Visual Studio 9.0\VC\bin\amd64\vcvarsamd64.bat
C:\Program Files\Microsoft Visual Studio 9.0\VC\bin\vcvars32.bat
C:\Program Files\Microsoft Visual Studio 9.0\VC\bin\x86_amd64\vcvarsx86_amd64.bat
C:\Program Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat

Links and references:
NMAKE Reference (MSDN)
An introduction to Makefiles
Nmake Makefile Tutorial and Example
CL Environment Variables
LINK Environment Variables
Setting the Path and Environment Variables for Command-Line Builds

Tuesday, 23 August 2011

How to set common paths in VS2010

"VC++ Directories change" paragraph in Visual Studio 2010 C++ Project Upgrade Guide says:

VC++ Directories are no longer supported in VS2010 through Tools->Options page. Instead, VS2010 introduces the user settings file (Microsoft.cpp..users.props) to control global settings including Global search path. These files are located at $(USERPROFILE)\appdata\local\microsoft\msbuild\v4.0 directory. Upon migration to VS2010, the custom settings of VC++ Directories from VS2005 or VS2008 are migrated to these user files. These global settings files are imported into all the converted and newly created projects.

Here are the steps to change the settings file through UI:

  • Open up property manager by clicking on View.Property Manager.
  • Expand the project node and then the Configuration|Platform nodes, you will see "Microsoft.cpp..users" file for each Configuration|Platform. These are the files for the global settings, similar to the old tools/Options/VC++ Directories.
  • Multi-Select "Microsoft.cpp..users", right click and bring up the property page window
  • In the property page window, click on "VC++ Directories" (for example) in the left pane, add new paths for the directories such as "Include Directories". separated by semicolons
  • Make sure to save the settings before shutting down Visual Studio.
  • Re-launch Visual Studio and the new settings will be in effect.


Note: If you would like to only change the settings for one project, you can right click on the project and bring up the property page. Change the settings for “VC++ Directories”, these settings will be persisted to the project file.

Thursday, 18 August 2011

Simple application with two panes and a splitter

Applications of this type are very common: we have some objects, or items, listed in a left pane and when we click on some item its attributes are displayed in the right pane. Items can be listed within a tree control, and right click context menu possibly provides actions we can perform on them. But let us focus now only on basic: a splitter window with two panes.

The quickest way to make application with such layout in MFC is by creating SDI (Single Document Interface) project. Document/View support is not required. Wizard creates CMainFrame class which is the main window of SDI application. Wizard also adds to it a View class - a child window that occupies the client area of the main frame:

Application looks like this:

SplitterTest1_5

We want to embed Splitter window into the main frame instead of this default View so we need to replace CChildView with instance of CSplitterWnd:

The right place to put code that creates controls in the main client area of the frame window is overloaded CFrameWnd::OnCreateClient.

Now how to overload parent's implementation of this method? The easiest way to insert various message handlers and overloads into MFC class is via class properties window:

  • go to class declaration in its header file
  • click on the class name
  • in the main menu in Visual Studio go to View->Other Windows->Properties Window
  • click Properties, Events, Messages or Overrides button in order to change properties or add event/messages handlers or to override base class methods

SplitterTest1_8

In this case, we click on Overrides, find and select OnCreateClient in the left side of the properties window, click in the value field and select Add OnCreateClient. This will automatically insert all necessary code in our class. This is default implementation of this overload:

We want to have static layout - left and right pane and a splitter bar all the time so will use CSplitterWnd::CreateStatic. Creating static splitter requires creating its panes within OnCreateClient.

A pane within a splitter window is usually a window derived from CView class. As we want to embed various controls (e.g. CTreeCtrl) in it, we will use CFormView, a class very similar to CDilaog. We could embed controls in a CView-derived class but using CFormView makes life simpler as allows using Visual Studio resource editor to design a form (properties, children controls) which is associated to CFormView object.

So how to add CFormView windows to our project? Just add a new Dialog in the resource editor and make sure its Style in Properties is set to Child. Optionally, remove Border and System menu. By default, this dialog has OK and Cancel button controls and we can leave them.

SplitterTest1_7

Right click on the dialog and pick "Add Class..." in order to associate a class with this resource. Select CFormView for the base class. I picked CLeftPaneFormView and CRightPaneFormView as names for my panes' classes.

SplitterTest1_6

Now when having panes ready, we can instruct our splitter to create them as its views:

If we run this application, we will see our dialogs with their children controls (OK and cancel buttons) embedded as the left and right pane in the splitter window - just what we wanted!

SplitterTest1_9

Throughout the code in main frame, panes can be accessed with this code:



Links and references:

TN029: Splitter Windows
MFC Tutorial
Visual C++ tutorial

Friday, 12 August 2011

How to make your application UAC compliant

From Vista onwards Microsoft has been using security technology called User Account Control (UAC) which aims to prevent malware execution.

User account groups in Windows OS (from Vista on) range from those that are fully limited (e.g. "Users" group) to those with fully unrestricted access to computer ("Administrators"). Upon log on, standard user gets session that is assigned with an access token with restricted privileges. Member of Administrators group gets session assigned with two tokens - one with restricted (filtered) and one with unrestricted (elevated) privileges. In both cases all applications are run by default in the security context of the user with restricted token. This is because user-initiated applications inherit access token from explorer.exe (desktop) which always runs with restricted token. So, even if user logs on as Administrator, application they run will not have elevated rights but only rights of the standard user. For most of the applications running with restricted rights is not a problem but what if application needs to change certain parts of the file system (e.g. write into "Program Files" directory) or registry (HKLM keys), areas for which elevated rights are required? It depends on the application manifest (described in the next paragraph) and account type of the logged on user.

User that runs some application does not know what privileges it needs in order to run properly. Program will fail if it requires unrestricted privileges but is run without elevation, no matter by which user. To prevent this, a simple solution was invented: application itself carries information which tells OS which privileges (execution level) it needs. They are written in a manifest, a part of resources embedded into executable. Applications with manifest are signed or UAC compliant (don't confuse this with the term 'digitally signed').

If standard user runs signed application that requires elevated privileges, they are prompted (UAC Credential Prompt) to enter Administrator's credentials. If Administrator runs such application, they still need to confirm they allow this program to run (UAC Consent Prompt). So, in both cases user is aware that application they run requires unrestricted privileges and it is not run automatically. This prevents programs (potentially malware) to run unnoticed which is the basic idea of UAC.

What about applications that are not UAC compliant? No matter which user runs it UAC Consent Prompt appears first and program is run with restricted privileges unless user use "Run as Administrator" context menu option in which case standard user is prompted for Administrator's credentials.

Microsoft strongly suggest making all application UAC compliant as in future Windows releases applications without manifest will not be able to run with elevated rights at all.

So, how we can make our application UAC compliant if developing in Visual Studio?

Add linker option /MANIFESTUACGo to Properties->Configuration Properties->Linker->Manifest File and set Enable User Account Control to Yes.

How to set execution level our application requests from OS?

Add level attribute and its value to the option /MANIFESTUAC: /MANIFESTUAC:level='value'. Set UAC Execution Level to one of the following values:
  • asInvoker - no elevation; application will run with same rights as its parent process (process that started it). E.g. if you run Windows Commander as Administrator, and then you run some executable from it, that executable will be run as Administrator as well. Be aware that Windows Explorer (desktop) run as standard users, even for Administrators so applications run from it will run as standard users as well!
  • highestAvailable - conditional elevation; application will get highest permissions it can. Standard user can run it only with its, restricted permissions. Administrator in admin-approval mode needs to retype its credentials in order to run this application with administrator rights (elevation takes place here). Otherwise application is run with restricted token. 
  • requireAdministrator - elevation takes place always; application will run only with elevated rights. Administrator will run it with elevated rights. Standard user will be prompted for Administrator's credentials.
There is one more attribute of UAC manifest, called UAC Bypass UI Protection (/uiAccess='[true|false]') which determines whether application run with restricted token can send Windows messages to applications running with full privileges. If set to false, it enables UI Privilege Isolation.


References and useful links:

User Account Control (Wikipedia)
User Account Control (MSDN)
Teach Your Apps To Play Nicely With Windows Vista User Account Control

Wednesday, 10 August 2011

Visual Studio, Directories and Environment Variables

Visual Studio 2010 does not allow setting user-specific paths to include files and libraries at the global level but instead these paths must be set in the user property sheet VC++ Directories which is automatically added to every project. Go to Properties->Configuration Properties->VC++ Directories and there you'll find various paths:

  • Executable Directories - path that corresponds to environmental directory PATH
  • Include Directories - path that corresponds to environmental directory INCLUDE
  • Reference Directories - path that corresponds to environmental directory LIBPATH
  • Library Directories - path that corresponds to environmental directory  LIB
  • Source Directories
  • Exclude Directories

The fact that Visual Studio treats these paths as if they were set in environment variables allows us to use the same semantics used when setting environment variables. E.g. we can reference value of some arbitrary environment variable in the path. For example, if WINDDK_PATH is environment variable which value is path to Windows DDK, we can reference its value as $(WINDDK_PATH). Path to DDK API headers in Include Directories is then $(WINDDK_PATH)\inc\api.

NOTE 1: Value of arbitrary environment variable named ENV_VAR can be echoed in Command Prompt window by executing "echo %ENV_VAR%" command.

NOTE 2: Visual Studio/Command Prompt  must be restarted in order to fetch latest changes in environment variables.