CSE 483 Windows Programming

Barbara Nostrand, Ph.D.

Electrical Engineering and Computer Science


Laboratory 3 - Working with Visual Studio 2005

  1. Overview

    In this lab exercise you’ll work with some of the more interesting features available in the Professional and Team Suite editions of Visual Studio 2005.
  2. Getting Started

    Download,  compile,  and try out the following .NET Hello World program: 
    	// HelloWorld3.cpp
    	
    	#include <stdio.h>
    	#include <iostream>
    	
    	int main() {
    	// use a C function to print "hello"
    	printf("hello");
    	
    	// use a C++ object to print a comma followed by a space
    	std::cout << ", ";
    	
    	// use a .NET class to print "world"
    	System::Console::WriteLine("world");
    	}
  3. C++/CLI for .NET uses colon pairs :: to separate classes,  objects,  and methods.  This usage is similar to the use of dot . in Java.  Live Java,  .NET code is managed code which for .NET code means that it is controlled at run time by the .NET run-time environment.  The .NET Common Language Infrastructure (CLI) is the application program interface (API) between C++ and the .NET run-time environment.  Commmon Language Runtime (CLR) implements this interface for the Microsoft Windows operating system.  However,  it is possible to implement a CLI runtime environment for most modern operating systems.  This in principle allows for easy portability for .NET software systems to other operating systems. 

  4. Compiling C++ for .NET

    Traditional C++ is compiled to native machine code.  C++/CLI must instead be compiled to managed code.  Consequently,  you must include the /clr switch when you complie a C++/CLI program from the command line: 

    	CL.EXE /clr HelloWorld3.cpp
    Since C++/CLI is a superset of traditional C++,  any legacy C++ program can be compiled for the .NET environment.  When a C++ file is compiled with the /clr switch,  the compiler generates a manqaged object file.  You can also compile any C++ library file for the .NET environment: 
    	CL.EXE /c /clr TheLib.cpp
    The /c switch tells the compiler to generate a managed object file which can be linked with other object files to produce a .NET application. 

  5. Linking Managed and Unmanaged Object Files

    Whenever the linker detects a managed object file among its inputs,  it automatically generates managed output for the .NET environment. 
  6. Calling unmanaged code from managed code

    All you have to do to call an unmanaged function from a managed function is declare the unmanaged frunction as external and call the function from within your managed code: 
    	// UnmanagedCode.cpp
    	// compile with "CL /c /EHs /MD UnmanagedCode.cpp"
    	
    	#include <iostream>
    	using namespace std;
    	
    	void fUmanaged()
    	{
    		cout << "Hello again from unmanaged code.\n" << endl;
    	}
    	
    	// ManagedCode.cpp
    	// compile with "CL /c /clr ManagedCode.cpp"
    	
    	extern void fUnmanaged();		// implemented in UnmanagedCode.cpp
    	
    	void fManaged()
    	{
    		System::Console::WriteLine("Greetings from managed code!");
    		fUnmanaged();
    	}
  7. Calling managed code from unamanged code

    Again,  all you need to do is define and call your functions in the normal way: 
    	// HelloWorld.cpp
    	// compile with "cl /MD HelloWorld.cpp /link ManagedCode.obj UnmanagedCode.obj"
    	
    	#include <stdio.h>
    
    	extern void fManaged();	// implemented in ManagedCode.cpp
    	
    	int main()
    	{
    		printf("Hi from native code.\n");
    		fManaged();
    	}
  8. Creating a Dynamic Link Library

    A dynamic link library (DLL) is a collection of small programs,  which can be called upon when needed by the executable program (EXE) that is running.  The DLL lets the executable communicate with a specific device such as a printer or may contain source code to do particular functions.  Creating a DLL can be an easy way to port an existing application to .NET.  This will allow your old application to use .NET features and execute in the managed .NET environment. 

    	// TheLib.cpp
    	// Compile with CL.EX /LD /clr TheLib.cpp
    	
    	extern "C"
    	_declspec(dllexport)
    	void f() { ... }
    	
    	
    
    	// TheApp.cpp
    	// Compile with CL.EX /c /MD /clr TheLib.cpp
    	
    	extern "C"
    	_delspec(dllimport)
    	void f();
    	
    	int main() { f(); }
    

    TheApp.cpp represents an existing project.  This project is extended with managed features by compiling TheLib.cpp to create a new DLL. 

  9. Designing and Implementing a Class

    The VS Team System lecture develops a Sailboat class using the Class Designer, Object Test Bench, Refactoring, and Code Snippets (see pages 1-10 .. 1-13 of the lecture). We’re going to do the same thing here, but with a different target class: MyDate. Startup Visual Studio, and create a new C# Console Application named Dates. Add a new class to the project: Project menu, Add Class, select Class from the list, and name it MyDate. This class will represent a date in a Gregorian (Western) calendar using 3 integers: Month, Day, and Year. Here’s the basic design: public class MyDate { public int Month; public int Day; public int Year; // constructor: public MyDate(int month, int day, int year) { ... } } Edit the class, add this code, and flush out the constructor. Now add a class diagram to the project: Project menu, Add New Item, Class Diagram. Switch to Class View (View menu), and drag-and-drop MyDate onto the designer surface. Right-click on the class and add a method NextDay( ), which will advance to the next valid date. Double-click on the method name in the designer, and this will take you back to the editor — notice the method is coded to throw an exception, which is fine for now. While you’re here in the editor, generate a ToString method — start typing public override, then use IntelliSense from there. Switch back to the Class Diagram, and notice the display is synchronized with the editor — ToString appears there as well. Code ToString to return a simple string like this: return string.Format("{0}/{1}/{2}", Month, Day, Year); Build and fix any syntax errors.
  10. Object Test Bench

    Let’s use the Object Test Bench to instantiate MyDate, and test the constructor and ToString methods. Right-click on MyDate in the class designer, or in the Solution Explorer (assuming you are in Class View). Create an instance, and supply a month, day and year — an object should be placed in the Object Test Bench (if the window isn’t visible, use View >> Other Windows). Inspect by hovering over the object and expanding the “+”. Right-click the object to invoke ToString. 

  11. Refactoring

    Return to the editor view of the class. Use the Refactoring menu to rename the fields to m_Month, m_Day, and m_Year. Then encapsulate the fields into properties. In front of each set method add the keyword private so that only the class itself may set the property. This is an example of an asymmetric property, where the get is public but the set is private. Asymmetric properties are a new feature in C# 2.0. Build and fix any errors. 

  12. Code Snippets

    Use a Code Snippet to generate the Equals and GetHashCode methods: Edit menu, IntelliSense, Insert Snippet, double-click on Visual C#, and double-click on equals. Code the Equals method (after the initial checks) to return true if all fields are the same: MyDate other; other = (MyDate)obj; return this.Month == other.Month && this.Day == other.Day && this.Year == other.Year; Code GetHashCode to return the sum of Month, Day, and Year. Actually, you can return whatever you want, as long as you follow this rule: two objects must return the same hash code if they are Equals.
  13. Coding and Testing

    Now code the NextDay method. The idea of NextDay is to increment the Day field, then see if it has wrapped around to the next month and year:
    if (Month == 1 || Month == 3 || ...)  // months with 31 days
    {
    	Day++;
    
    	if (Day == 32)  // next month!
    	{
    	Day = 1;
    	Month++;
    
    	if (Month > 12)  // next year!
    	{
    		Month = 1;
    		Year++;
    	}
    }
    }
    else ...
    

    Keep things simple, and don’t worry about leap years. In fact, take some short-cuts and introduce some errors for us to catch during unit testing. Or better yet, open the solution (Labs\Solution) and copy-paste some code to save time. Build and fix any errors. 

    Now use the Object Test Bench to instantiate and test your work. After invoking NextDay, inspect the object to convince yourself that the date has indeed changed within the object. 

    That’s it, good work! Take a break…

Working with VS 2005 Team System

  1. Overview

    In this lab exercise you’ll work with some of the software engineering features available in the Team Suite edition of Visual Studio 2005. 
  2. Unit Testing

    Let’s start by opening your work from the previous lab exercise — MyDate. It’s perfectly fine if you didn’t complete the class; all you need is something that compiles. 

    As discussed on pages 1-21 .. 1-23 of the lecture, add a test harness to your Visual Studio project: Test menu, New Test, select Unit Test, be sure to create a new C# test project, name the test MyDateTestHarness, and name the new project DatesTestHarnesses. Go ahead and build the solution. If you get an error that Visual Studio “cannot find MyDate”, you’ll need to add a reference from the DatesTestHarness project to the Dates project, as follows:

    The test harness will now have access to the MyDate class.  Now the solution should build without error. 

    Edit the MyDateTestHarness class, and import the Dates namespace with a using statement: 

    	using Dates;

    Now write one or two test methods following the example in the lecture. Here’s one: 

    	[TestMethod]
    	public void TestMethod1()
    	{
    	  MyDate d;
    	  d = new MyDate(12, 31, 2006);
    	  d.NextDay();
    
    	  Assert.IsTrue(d.Month == 1 && d.Day == 1 && d.Year == 2007);
    	}
    Intentionally write another test case that fails. Run and check the results — if you are pressing F5 to run, make sure your test harness is set as the startup project (it should be in boldface, if not, right-click on the project in the Solution Explorer and select “Set as Startup Project”). Fix the test case that failed — or the underlying class depending on the error — and rerun the tests.
  3. Code Coverage

    As discussed in the lecture (1-25 .. 1-27), enable code coverage, run without debugging, and collect code coverage statistics. After the run, drill-down into the code from the code coverage results pane to see how Visual Studio uses code-coloring to convey covered vs. uncovered code. 
  4. Visual Studio Team System

    To finish the exercise, let’s create a new Team project and check-in the code for your class and test harness. The overall concept is discussed on pages 1-30 .. 1-33 of the lecture. Before you begin, recall that interacting with a Visual Studio Team Foundation Server requires that the client — you — have (1) a Team edition of Visual Studio 2005, and (2) the Team Explorer plug-in installed. 

    For this particular lab setup, connect to the TFS named “TFSRTM”,  with the username “attendee” and the password “pop123”.  This username has administrative rights on the TFS to create Team projects.  Since everyone will be using the same username to connect,  create your new Team project with a unique name — based on say your first and last name.  After you check-in the code,  add another test method, and notice how the icon in Visual Studio’s Solution Explorer changes for that source code file.  Check-in the pending updates as discussed on page 1-35. 

    That’s it, good work! Take a break…
    Last modified: 2008 JAN 28
    bnostran@syr.edu