Earlier this year I published a series of articles on Codeguru about WP7 Silverlight development. Later on I have remastered them a bit and merged them together with a couple of articles by Vipul Patel into a small eBook that was published on internet.com, called Windows Phone 7 Quick Start Developer Guide. There is also a ZIP archive with the source code for all the sample projects presented throughout the book. While you can still find the articles online on the site, I recommend the eBook as a better learning material as it puts the various topics together.

The eBook is intended for developers with a fair knowledge of .NET programming that want to start developing Silverlight applications for Windows Phone 7. However, it is not a complete guide to Silverlight development for Windows Phone 7. The eBook covers a smaller set of Silverlight topics that is intended to prepare the reader for the most common challenges a Windows Phone 7 developer faces.

Here is the table of contents of the eBook.

  • Preface
  • Where to Start
  • Creating a Simple Windows Phone Application: “Hello World!”
  • The Application Bar
  • Page Navigation
  • Tombstoning and Data Persistence
  • Pivot and Panorama
  • Launchers and Choosers
  • Touch
  • Using Bing Maps Control
  • App Hub: Application Submission Walkthrough
  • References
  • About the Authors

Download the eBook from here.

, , , Hits for this post: 4833 .

There was a question on Stackoverflow about a C++ project displaying an image as you type. Here is the original question:

I am writing a very simple program in C++ that listens to keyboard input, but what I want to output is much more difficult than I expected. For every key I press, I want an image (specific to the key) to appear on the screen. For example, let’s say if I press the “O” key, an image of Earth appears on my screen.

It sounded like a fun exercise to do in C++ using Windows API. So here is my quick answer, a simple solution to the problem.

I wanted to display three different images, an earth, a moon and a sun, when the user types E, M or S in the window. The images should use transparency, so I decided to use PNG files. Here is how the images look.


A good option for loading PNG files is using Windows Imaging Component. The point would be to add the PNG files to the project resources, then use WIC to load them and create an HBITMAP that would be used later to display the image. Bradley Grainger had just the right code on his blog. This is how it looks, except that I made some slight modifications to LoadImageFromResources (called LoadSplashImage on his blog).

IStream* CreateStreamOnResource(LPCTSTR lpName, LPCTSTR lpType)
{
   IStream * ipStream = NULL;

   HRSRC hrsrc = FindResource(NULL, lpName, lpType);
   if (hrsrc == NULL)
      goto Return;

   DWORD dwResourceSize = SizeofResource(NULL, hrsrc);
   HGLOBAL hglbImage = LoadResource(NULL, hrsrc);
   if (hglbImage == NULL)
      goto Return;

   LPVOID pvSourceResourceData = LockResource(hglbImage);
   if (pvSourceResourceData == NULL)
      goto Return;

   HGLOBAL hgblResourceData = GlobalAlloc(GMEM_MOVEABLE, dwResourceSize);
   if (hgblResourceData == NULL)
      goto Return;

   LPVOID pvResourceData = GlobalLock(hgblResourceData);

   if (pvResourceData == NULL)
      goto FreeData;

   CopyMemory(pvResourceData, pvSourceResourceData, dwResourceSize);

   GlobalUnlock(hgblResourceData);

   if (SUCCEEDED(CreateStreamOnHGlobal(hgblResourceData, TRUE, &ipStream)))
      goto Return;

FreeData:
   GlobalFree(hgblResourceData);

Return:
   return ipStream;
}

IWICBitmapSource* LoadBitmapFromStream(IStream * ipImageStream)
{
   IWICBitmapSource* ipBitmap = NULL;

   IWICBitmapDecoder* ipDecoder = NULL;
   if (FAILED(CoCreateInstance(CLSID_WICPngDecoder, NULL, CLSCTX_INPROC_SERVER,
                               __uuidof(ipDecoder), reinterpret_cast<void**>(&ipDecoder))))
      goto Return;

   if (FAILED(ipDecoder->Initialize(ipImageStream, WICDecodeMetadataCacheOnLoad)))
      goto ReleaseDecoder;

   UINT nFrameCount = 0;
   if (FAILED(ipDecoder->GetFrameCount(&nFrameCount)) || nFrameCount != 1)
      goto ReleaseDecoder;

   IWICBitmapFrameDecode* ipFrame = NULL;
   if (FAILED(ipDecoder->GetFrame(0, &ipFrame)))
      goto ReleaseDecoder;

   WICConvertBitmapSource(GUID_WICPixelFormat32bppPBGRA, ipFrame, &ipBitmap);
   ipFrame->Release();

ReleaseDecoder:
   ipDecoder->Release();
Return:
   return ipBitmap;
}

HBITMAP CreateHBITMAP(IWICBitmapSource* ipBitmap)
{
   HBITMAP hbmp = NULL;

   UINT width = 0;
   UINT height = 0;
   if (FAILED(ipBitmap->GetSize(&width, &height)) || width == 0 || height == 0)
      goto Return;

   BITMAPINFO bminfo;

   ZeroMemory(&bminfo, sizeof(bminfo));
   bminfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
   bminfo.bmiHeader.biWidth = width;
   bminfo.bmiHeader.biHeight = -((LONG) height);
   bminfo.bmiHeader.biPlanes = 1;
   bminfo.bmiHeader.biBitCount = 32;
   bminfo.bmiHeader.biCompression = BI_RGB;

   void * pvImageBits = NULL;
   HDC hdcScreen = GetDC(NULL);
   hbmp = CreateDIBSection(hdcScreen, &bminfo, DIB_RGB_COLORS, &pvImageBits, NULL, 0);
   ReleaseDC(NULL, hdcScreen);
   if (hbmp == NULL)
      goto Return;

   const UINT cbStride = width * 4;
   const UINT cbImage = cbStride * height;
   if (FAILED(ipBitmap->CopyPixels(NULL, cbStride, cbImage, static_cast<BYTE*>(pvImageBits))))
   {
      DeleteObject(hbmp);
      hbmp = NULL;
   }

Return:
   return hbmp;
}

HBITMAP LoadImageFromResources(LPCTSTR lpName, LPCTSTR lpType)
{
   HBITMAP hbmpSplash = NULL;

   IStream* ipImageStream = CreateStreamOnResource(lpName, lpType);
   if (ipImageStream == NULL)
      goto Return;

   IWICBitmapSource* ipBitmap = LoadBitmapFromStream(ipImageStream);
   if (ipBitmap == NULL)
      goto ReleaseStream;

   hbmpSplash = CreateHBITMAP(ipBitmap);
   ipBitmap->Release();

ReleaseStream:
   ipImageStream->Release();

Return:
   return hbmpSplash;
}

However for this to work the following are necessary:

#include <Objidl.h>
#include <Wincodec.h>

#pragma comment (lib, "windowscodecs.lib")

Objidl.h is required for IStream, while Wincodec.h and windowscodecs.lib for WIC.

I have created a Win32 Project, called TypePictures. The wizard generates the backbone for the app, but I’ll not talk about that part. Besides adding the functions listed above, I also added the following:

HWND g_hPictureWnd = NULL;
HBITMAP g_hbmp;
UINT_PTR g_timer = 0;
const TCHAR c_szPictureClass[] = _T("myPictureWindow");

ATOM RegisterPictureWindowClass(HINSTANCE hInstance);
BOOL CreatePictureWindow(HINSTANCE hInstance, HWND hOwner);
BOOL DestroyPictureWindow();
BOOL SetPicture(HBITMAP hbmp);
VOID CALLBACK PictureTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);

hPictureWnd is the handle to the window that displays the image, g_timer is a timer used for automatically closing the window after a desire interval, and g_hbmp is the handle to the current loaded image.

RegisterPictureWindowClass registers the window class for the picture window. It uses the c_szPictureClass defined earlier for the class name.

ATOM RegisterPictureWindowClass(HINSTANCE hInstance)
{
   WNDCLASSEX wcex = {0};

   wcex.cbSize = sizeof(WNDCLASSEX);

   wcex.lpfnWndProc	= DefWindowProc;
   wcex.cbClsExtra	= 0;
   wcex.cbWndExtra	= 0;
   wcex.hInstance	= hInstance;
   wcex.hIcon		= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TYPEPICTURES));
   wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
   wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
   wcex.lpszClassName	= c_szPictureClass;
   wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

   return RegisterClassEx(&wcex);
}

This will be called in the main function before the call to InitInstance.

RegisterPictureWindowClass(hInstance);

CreatePictureWindow is a function that creates the picture window. This will be a layered window that we’ll later update with UpdateLayeredWindow when displayined the picture.

BOOL CreatePictureWindow(HINSTANCE hInstance, HWND hOwner)
{
   if(g_hPictureWnd != NULL)
      return FALSE;

   RECT rcwin;
   GetWindowRect(hOwner, &rcwin);

   g_hPictureWnd = ::CreateWindowEx(
      WS_EX_LAYERED,
      c_szPictureClass,
      NULL,
      WS_POPUP | WS_VISIBLE,
      rcwin.right+1, rcwin.top, 128, 128,
      hOwner,
      NULL,
      hInstance,
      NULL);

   return g_hPictureWnd != NULL;
}

DestroyPictureWindow does what the name implies, it destroys the layered window that displays the picture.

BOOL DestroyPictureWindow()
{
   if(g_hPictureWnd == NULL)
      return FALSE;

   BOOL ret = DestroyWindow(g_hPictureWnd);
   g_hPictureWnd = NULL;

   return ret;
}

SetPicture is a key function that displays a bitmap in the layered window. It takes the bitmap that was loaded from an PNG with LoadImageFromResources and displays it in the layered window. As mentioned earlier it calls UpdateLayeredWindow to update the window.

BOOL SetPicture(HBITMAP hbmp)
{
   if(g_hPictureWnd == NULL)
      return FALSE;

   BITMAP bm;
   GetObject(hbmp, sizeof(bm), &bm);
   SIZE sizebmp = {bm.bmWidth, bm.bmHeight};

   HDC hdcScreen = GetDC(g_hPictureWnd);
   HDC hdcMem = CreateCompatibleDC(hdcScreen);
   HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcMem, hbmp);

   BLENDFUNCTION blend = { 0 };
   blend.BlendOp = AC_SRC_OVER;
   blend.SourceConstantAlpha = 255;
   blend.AlphaFormat = AC_SRC_ALPHA;

   RECT rcwin;
   GetWindowRect(g_hPictureWnd, &rcwin);

   POINT ptSrc = {0};
   POINT ptDest = {rcwin.left, rcwin.top};

   UpdateLayeredWindow(
      g_hPictureWnd,
      hdcScreen,
      &ptDest,
      &sizebmp,
      hdcMem,
      &ptSrc,
      RGB(0, 0, 0),
      &blend,
      ULW_ALPHA);

   SelectObject(hdcMem, hbmpOld);
   DeleteDC(hdcMem);
   ReleaseDC(g_hPictureWnd, hdcScreen);

   return TRUE;
}

PictureTimerProc is the timer procedure we use to destroy the window after a specified interval since the last typed key elapsed.

VOID CALLBACK PictureTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
   if(idEvent == g_timer)
   {
      ::KillTimer(hwnd, idEvent);
      g_timer = 0;

      DestroyPictureWindow();
   }
}

Make sure you call CoInitialize() to initialize the COM library for the main thread before the message loop begins in function main. Also make sure to call CoUninitialize() before the program ends.

WndProc is the function where the messages sent to the main window are processed. We’ll handle WM_CHAR, and when E, M or S are pressed we load the appropriate image, create the layered window for the picture if not already created, and set the picture in the window. This is how the code looks:

   case WM_CHAR:
      {
         HBITMAP hbmp = NULL;
         switch((char)wParam)
         {
         case 'E': case 'e':
            hbmp = LoadImageFromResources(MAKEINTRESOURCE(IDB_PNG1), _T("PNG"));
            break;
         case 'M': case 'm':
            hbmp = LoadImageFromResources(MAKEINTRESOURCE(IDB_PNG2), _T("PNG"));
            break;
         case 'S': case 's':
            hbmp = LoadImageFromResources(MAKEINTRESOURCE(IDB_PNG3), _T("PNG"));
            break;
         default:
            break;
         }

         if(hbmp != NULL)
         {
            if(g_hbmp != NULL)
               DeleteObject(g_hbmp);
            g_hbmp = hbmp;

            if(g_hPictureWnd == NULL)
            {
               CreatePictureWindow(hInst, hWnd);
            }

            if(g_hPictureWnd != NULL)
            {
               if(SetPicture(hbmp))
               {
                  g_timer = SetTimer(hWnd, 1, 2000, PictureTimerProc);
                  SetFocus(hWnd);
               }
            }
         }
      }
      break;

And basically that is all. Just run the application and type E, M and S. You’ll see the images changing and 2 seconds after the last key is pressed the image is automatically hidden (as the layered window is destroyed).

You can download the source code from here: TypePictures (219).

, , , Hits for this post: 5293 .

I recently ran across a bug with an application ported to the x64 platform. After debugging the application the error turned to be due to integrals layout and casting. I think this is a typical example worth mentioning.

It starts with this definition:

#define COMBO_VALUE -99

which is used for a combo box with SetItemData:

pCombo->SetItemData(index, (DWORD)COMBO_VALUE);

Notice the cast to DWORD, which is an integral type represented on 32-bits both on x86 and x64. At a later point this value was retrieved and tested against COMBO_VALUE:

if (pCombo->GetItemData(pCombo->GetCurSel()) == COMBO_VALUE)

They key here is how the value of -99 is represented:

  32-bit platform 64-bit platform
-99 FFFFFF9D FFFFFFFFFFFFFF9D
(DWORD)-99 FFFFFF9D FFFFFF9D
(DWORD_PTR)-99 FFFFFF9D FFFFFFFFFFFFFF9D
(DWORD_PTR)(DWORD)-99 FFFFFF9D 00000000FFFFFF9D

GetItemData returns a DWORD_PTR, so FFFFFF9D becomes 00000000FFFFFF9D on x64. Then -99 is also interpreted as a DWORD. Thus the condition in the above if statement resolves to 00000000FFFFFF9D == FFFFFFFFFFFFFF9D on x64, which of course is false.

To fix the problem, the if statement should be re-written like this:

if ((DWORD)pCombo->GetItemData(pCombo->GetCurSel()) == COMBO_VALUE)

A very simply fix, but not so simple to spot the root of the problem when just reading the code.

, , , Hits for this post: 5982 .

If you include in a VC++ project <mapidefs.h> and <sqltypes.h> and build for the x64 platform you get a redefinition error.

#include <Windows.h>
#include <MAPIDefS.h>
#include <sqltypes.h>

int _tmain(int argc, _TCHAR* argv[])
{
	return 0;
}

1>C:\Program Files\Microsoft SDKs\Windows\v6.0A\include\sqltypes.h(283) : error C2371: ‘BOOKMARK’ : redefinition; different basic types
1> C:\Program Files\Microsoft SDKs\Windows\v6.0A\include\MAPIDefS.h(1142) : see declaration of ‘BOOKMARK’

The reason is that BOOKMARK is defined in both files.

This is mapidefs.h

typedef ULONG 		BOOKMARK;

This is sqltypes.h

typedef SQLULEN         BOOKMARK;

On x86, both ULONG and SQLULEN are an unsigned long. However, on x64, ULONG is still unsigned long, but SQLULEN is an UINT64, which is different than unsigned long. Hence the error.

There is a Connect bug report called Using x64 with mapidefs.h and sqltypes.h causes C2371 filed by Martin Richter 6 years ago (!), with no fix yet. Martin proposed the following workaround:

#undef BOOMARK
#define BOOMARK MAPI_BOOKMARK
#include <mapidefs.h>
#undef BOOMARK
#define BOOMARK SQL_BOOKMARK
#include <sqltypes.h>
#undef

However, it doesn’t work for me. I get the very same error. To get rid of the error you have to use namespaces. Define two namespaces, let’s call them MAPI and SQL and include each header in one of them. Then you can use the using namespace directive so that you don’t have to prefix everything with MAPI:: or SQL::. However, you’ll have to use the fully qualified name when you want to use one or the other BOOKMARK, as shown in the following example:

#include <Windows.h>

namespace MAPI
{
#include <mapidefs.h>
}

namespace SQL
{
#include <sqltypes.h>
}

using namespace MAPI;
using namespace SQL;

int _tmain(int argc, _TCHAR* argv[])
{
   SQL::BOOKMARK bookmark = 0;

   return 0;
}
, , , , Hits for this post: 9478 .

At the beginning of this year, Microsoft announced a “C++ renaissance”. Quoting from the description of a Channel 9 video with Craig Symonds and Mohsen Agsen:

C++ is currently undergoing a renaissance. This means that, by definition, the language, compilers and compositional tooling are evolving and coalescing into a state that maximizes native developer efficiency, productivity, and creativity across hardware and software domains.

Everybody agrees that Microsoft made C++ a sort of second class citizen in the past years, while the company invested a lot in the .NET framework. Many developers have switched from native development to managed (.NET) simply because it offers a more productive environment. And the postponing of the ISO standard committee in releasing the new C++0x standard only made things worse.

However, with the completion of the new C++ standard this year, Microsoft, apparently, plans to change that, and make C++ again appealing to developers. They already made C++0x features available in the VS2010 C++ compiler and are working on implementing most of the rest for Visual Studio vNext. They are also investing in tools (now labeled Application Lifecycle Management), and for instance are bringing intellisence to C++/CLI. One of the most important areas of development is parallelism, where they are developing the PPL and Agents libraries and now the C++ AMP that they just announced. And also recently the Kinect for Windows SDK beta that provides Kinect capabilities to developers who build applications with C++ (and other laguanges). And in the mean time they hired Erich Gamma in the Visual Studio team.

But this is not enough in my opinion. Improvements in language and tools are an important part, but not everything. It is equally necessary for Microsoft to evangelize it, using any necessary means. Unless they can spread the word, the work might pass unnoticed. To be honest, I was very reluctant about this part, half an year ago, when they announced the “renaissance”. However, looking back at what they done I’d say they are on the right track. Of course, there is still a lot of work to match the “advertising” effort put into .NET. But right now C++ is getting more attention at conferences such as PDC or TechEd, or their publishing assets, such as Channel 9, MSDN or their team blogs. So I tried to assemble a collection of videos, blogs, books and code samples related to C++ or native development that they published since the announcement of the renaissance. So far it looks good, in my opinion.

Channel 9
E2E: Herb Sutter and Erik Meijer – Perspectives on C++
Craig Symonds and Mohsen Agsen: C++ Renaissance
Windows 7 Taskbar Integration for MFC Applications
Tony Goodhew: VC++ Developer Communication – Questions and Answers
Talkin’ C++ with Kate Gregory
MVP Summit 2011: Meet C++ MVPs Angel, PJ, Tom and Sheng
Talkin’ C++ with Alon, Marius, Bruno, and Jim
Talkin’ C++ with Boris Jabes: C++ Intellisense, Game Development, and Boris Faces His Demons
Application Restart and Recovery on Windows 7 in Native Code
Parallel Programming for C++ Developers: Tasks and Continuations, Part 1 of 2
Parallel Programming for C++ Developers: Tasks and Continuations, Part 2 of 2
Conversation with Herb Sutter: Perspectives on Modern C++(0x/11)
First Look: New ALM Tools for VC++ Developers
Modern Native C++ Development for Maximum Productivity
Mohsen Agsen – C++ Today and Tomorrow
Herb Sutter: C++ Questions and Answers
Herb Sutter – Heterogeneous Computing and C++ AMP
Daniel Moth: Blazing-fast code using GPUs and more, with C++ AMP
C9 Lectures: Stephan T Lavavej – Advanced STL, 1 of n
C9 Lectures: Stephan T Lavavej – Advanced STL, 2 of n
C9 Lectures: Stephan T Lavavej – Advanced STL, 3 of n
C9 Lectures: Stephan T Lavavej – Advanced STL, 4 of n
C9 Lectures: Stephan T Lavavej – Advanced STL, 5 of n

Visual C++ Team Blog
Grr… My VC++ Project Is Building Slower in VS2010. What Do I Do Now? (A Step by Step Guide)
C++/CLI IntelliSense in Visual Studio vNext
Exception Boundaries: Working With Multiple Error Handling Mechanisms
Troubleshooting Tips for IntelliSense Slowness
Build Related Improvement in VS2010 SP1
Converting An MFC Ribbon To Designer Format
Enforcing Correct Concurrent Access of Class Data

Parallel Programming in Native Code Blog
Sorting in PPL
How to pick your parallel sort?
The Concurrency Runtime and Visual C++ 2010: Lambda Expressions
The Concurrency Runtime and Visual C++ 2010: Automatic Type Deduction
The Concurrency Runtime and Visual C++ 2010: The decltype Type Specifier
The Concurrency Runtime and Visual C++ 2010: Rvalue References
The Concurrency Runtime and Visual C++ 2010: Transporting Exceptions between Threads
Building Responsive GUI Applications with PPL Tasks

MSDN Magazine
Writing a Debugging Tools for Windows Extension
Writing a Debugging Tools for Windows Extension, Part 2: Output
Writing a Debugging Tools for Windows Extension, Part 3: Clients and Callbacks
Agile C++ Development and Testing with Visual Studio and TFS

Books & Publications
Parallel Programming with Microsoft Visual C++
The Visual C++ Weekly

Code & Samples
Code samples for the Concurrency Runtime and Parallel Pattern Library in Visual Studio 2010
Bing Maps Trip Optimizer
Hilo: Developing C++ Applications for Windows 7
All-in-One Code Framework

, , , Hits for this post: 11235 .

Microsoft has recently announced at the AMD Fusion Developer Summit the introduction of a new technology called C++ Accelerated Massive Parallelism or shortly C++ AMP that helps C++ developers use the GPU for parallel programming. The new technology will be part of Visual C++, integrated with full support (edit, build, debug, profile) in the next version of Visual Studio. It is built in modern C++ on top of DirectX. It will provide an STL-like library, part of the Concurrency namespace, delivered in a amp.h header.

S.Somasegar (Senior Vice President of the Developer Division) said:

By building on the Windows DirectX platform, our implementation of C++ AMP allows you to target hardware from all the major hardware vendors. We expect that it will be part of the next Visual C++ compiler and fully integrated in the next release of Visual Studio experience.

You can read more about it here:

Looking forward for the first CTP and samples.

UPDATE
Herb Sutter introduces C++ AMP at the AMD Fusion Developer Summit 11

Daniel Moth digs deeper into C++ AMP with code samples and more

Herb Sutter

How long is your password? How long it will take a 100,000,000 GPU cores running at what, a million attempts per second to crack your password just by brute force? That where almost a kid can write that. An that is just a tiny example of how game changing this is.

, , , , Hits for this post: 10362 .

Last year I posted a small MFC application on my blog, called Colors Game, about covering with a single color a grid initially colored in six colors. It wasn’t a big deal of an application, but it was fun and recently I decided to write a WPF version of that MFC game. This is the result:

The game is about covering in a single color a grid that starts with each cell colored randomly with one of six possible colors. You must expand the working region initially defined my the top-left cell throughout the entire grid. You select to color this working region with a new color that should match the color of neighboring cells. These cells are then merged into the working region. The game ends when you covered the grid in a single color. However, each level has a maximum allowed number of moves (or colorings) that you can do, and you only complete (or win) the level if you don’t exceed this number.

The image below shows how the working region expands towards the entire grid.

This new game has a more appealing interface and a richer set of features:

  • can select any of the available levels
  • you can change color themes for windows and for the grid
  • view statistics about your previous plays in any level
  • progress and settings are stored on disk and automatically reloaded when starting the application again

The game is described in details on this dedicated page. If you download an install the game, you should read that before playing.

If you find the game too easy, then I propose to use one of the more challenging color themes such as the Back and White one. Here is a screenshot:

Download the latest version of the game from here and enjoy it!

Hits for this post: 3693 .

I said it before, the Visual Studio installer gets me mad. All is fine until you want to install the Service Pack. After that you cannot install additional components until you uninstall the SP. Because of that, you should make sure you installed the entire Visual Studio package before installing SP1. So I did, but it proved not enough. Here is the story of what happened today.

  1. I installed Visual Studio 2010 Ultimate on my machine (a couple of weeks ago).
  2. I installed Visual Studio 2010 SP1. So far all was good, I was able to use it with no problems.
  3. But then I decided to install the Windows Phone developer tools, following the steps described on this page. After that, when I started Visual Studio 2010 I got this message that SP1 was applied only partially and in order to start the application it must be applied to all components (which was weird because I did that before a couple of times and everything was fine).
  4. I have installed the SP1 again. Then, when I started VS2010 it worked.
  5. However, I wanted to install the Visual Studio Visualization and Modeling SDK to be able to automatically build my text templates when building the solutions, as described here. This SDK needed Visual Studio 2010 SDK installed on the machine. But when I ran the installer for the SDK I got the following error:

    Obviously the error message was non-sense, not only I had VS2010 installed, but it had all the components, and the service pack was applied. Knowing the problems with the service pack, I immediately figured it was the reason.

  6. I have uninstalled the Visual Studio 2010 SP1. Of course, while it was uninstalling it crashed, so I had to start it again.

  7. I started the Visual Studio 2010 installer just to make sure I had all the components installed. However, I ran into this error:

    After several failed attempts I decided to restart Windows. That did the trick and the installer started correctly and I could make sure all the components were there.

  8. I installed Visual Studio 2010 SDK successfully.
  9. I installed Visual Studio Visualization and Modeling SDK successfully.
  10. I installed Visual Studio 2010 SP1 successfully.

Then, three hours later, I could start working with Visual Studio 2010 again. Text templates are automatically built, and the Windows Phone tools are working correctly.

Puff!

, , , Hits for this post: 8687 .

Text templates (aka T4) is a great feature in Visual Studio, that proves helpful in many scenarios. I use it for instance in developing Alchemy. However, it has a significant drawback: it does not generate code automatically when you build your solution. To build the files and generate their output you have to manually run either Run Custom Tool command for each .tt file, or Transform All Templates for the entire solution.

Run Custom Tool

Transform All Templates

The good news is that Visual Studio 2010 has added capabilities for building the text templates files automatically at the build time. Basically, what you have to do is two things: first install the Visual Studio Visualization and Modeling SDK. Second, manually add the following to the project file:

   <PropertyGroup>
      <TransformOnBuild >true</TransformOnBuild>
   </PropertyGroup>

   <Import Project=
     "$(MSBuildExtensionsPath)\Microsoft\VisualStudio\TextTemplating\v10.0\Microsoft.TextTemplating.targets" />

And that should do the trick. When you build the project, the .tt files will also be built.

To read more about this topic see:

, , , , Hits for this post: 10766 .

Finding applications installed on a machine (the ones that you see in Control Panel Add/Remove programs) could be a little bit tricky, because there isn’t a bulletproof API or method. Each of the available methods has its own weak points. WMI is slow and can actually be disabled on a machine. MSI API only shows applications installed with an MSI, and reading directly from the Windows Registry is not an officially supported alternative. Thus it is an open point which one is the most appropriate, though the official answer will probably be MSI API.

In this post I will go through all of these three methods and show how to query for the installed applications and display the name, publisher, vendor and installation location (if available). Notice these are just some samples, and if you want to use this in your applications you’ll probably want to do additional things like better error checking. Because I want the code to work both with ANSI and UNICODE I will use the following defines

#include 
#include 

#ifdef _UNICODE
#define tcout       wcout
#define tstring     wstring
#else
#define tcout       cout
#define tstring     string
#endif

WMI
Win32_Product is a WMI class that represents a product installed by Windows Installer. For fetching the list of installed applications with WMI I will reuse the WMIQuery class I first shown in this post. You need to include Wbemidl.h and link with wbemuuid.lib.

In the code shown below WmiQueryValue() is a function that reads a property from the current record and returns it as an STL string (UNICODE or ANSI). WmiEnum() is a function that fetches and displays in the console all the installed applications.

class WMIQuery
{
   IWbemLocator* m_pLocator;
   IWbemServices* m_pServices;

public:
   WMIQuery():
      m_pLocator(NULL),
      m_pServices(NULL)
   {
   }

   bool Initialize()
   {
      // Obtain the initial locator to WMI
      HRESULT hr = ::CoCreateInstance(
         CLSID_WbemLocator,
         0,
         CLSCTX_INPROC_SERVER,
         IID_IWbemLocator, (LPVOID *) &m_pLocator);

      if (FAILED(hr))
      {
         cerr << "Failed to create IWbemLocator object. Err code = 0x" << hex << hr << endl;
         return false;
      }

      // Connect to WMI through the IWbemLocator::ConnectServer method
      // Connect to the root\cimv2 namespace with the current user
      hr = m_pLocator->ConnectServer(
         _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
         NULL,                    // User name. NULL = current user
         NULL,                    // User password. NULL = current
         0,                       // Locale. NULL indicates current
         NULL,                    // Security flags.
         0,                       // Authority (e.g. Kerberos)
         0,                       // Context object
         &m_pServices             // pointer to IWbemServices proxy
         );

      if (FAILED(hr))
      {
         cerr << "Could not connect. Error code = 0x" << hex << hr << endl;
         m_pLocator->Release();
         m_pLocator = NULL;
         return false;
      }

      // Set security levels on the proxy
      hr = ::CoSetProxyBlanket(
         m_pServices,                 // Indicates the proxy to set
         RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx
         RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx
         NULL,                        // Server principal name
         RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx
         RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
         NULL,                        // client identity
         EOAC_NONE                    // proxy capabilities
         );

      if (FAILED(hr))
      {
         cerr << "Could not set proxy blanket. Error code = 0x" << hex << hr << endl;
         m_pServices->Release();
         m_pServices = NULL;
         m_pLocator->Release();
         m_pLocator = NULL;
         return false;
      }

      return true;
   }

   IEnumWbemClassObject* Query(LPCTSTR strquery)
   {
      IEnumWbemClassObject* pEnumerator = NULL;
      HRESULT hr = m_pServices->ExecQuery(
         bstr_t("WQL"),
         bstr_t(strquery),
         WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
         NULL,
         &pEnumerator);

      if (FAILED(hr))
      {
         cerr << "Query for operating system name failed. Error code = 0x" << hex << hr < endl;
         return NULL;
      }

      return pEnumerator;
   }

   ~WMIQuery()
   {
      if(m_pServices != NULL)
      {
         m_pServices->Release();
         m_pServices = NULL;
      }

      if(m_pLocator != NULL)
      {
         m_pLocator->Release();
         m_pLocator = NULL;
      }
   }
};

tstring WmiQueryValue(IWbemClassObject* pclsObj,
                      LPCWSTR szName)
{
    tstring value;

    if(pclsObj != NULL && szName != NULL)
    {
        VARIANT vtProp;

        HRESULT hr = pclsObj->Get(szName, 0, &vtProp, 0, 0);
        if(SUCCEEDED(hr))
        {
            if(vtProp.vt == VT_BSTR && ::SysStringLen(vtProp.bstrVal) > 0)
            {
#ifdef _UNICODE
                value = vtProp.bstrVal;
#else
                int len = ::SysStringLen(vtProp.bstrVal)+1;
                if(len > 0)
                {
                    value.resize(len);
                    ::WideCharToMultiByte(CP_ACP,
                                          0,
                                          vtProp.bstrVal,
                                          -1,
                                          &value[0],
                                          len,
                                          NULL,
                                          NULL);
                }
#endif
            }
        }
    }

    return value;
}

void WmiEnum()
{
    HRESULT hres;

    // Initialize COM.
    hres =  ::CoInitializeEx(0, COINIT_MULTITHREADED);
    if (FAILED(hres))
    {
        cout << "Failed to initialize COM library. Error code = 0x" << hex << hres << endl;
        return;
    }

    // Set general COM security levels
    hres =  ::CoInitializeSecurity(
        NULL,
        -1,                          // COM authentication
        NULL,                        // Authentication services
        NULL,                        // Reserved
        RPC_C_AUTHN_LEVEL_DEFAULT,   // Default authentication
        RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
        NULL,                        // Authentication info
        EOAC_NONE,                   // Additional capabilities
        NULL                         // Reserved
        );

    if (FAILED(hres))
    {
        cout << "Failed to initialize security. Error code = 0x" << hex << hres << endl;
        ::CoUninitialize();
        return;
    }
    else
    {
        WMIQuery query;
        if(query.Initialize())
        {
            IEnumWbemClassObject* pEnumerator = query.Query(_T("SELECT * FROM Win32_Product"));

            if(pEnumerator != NULL)
            {
                // Get the data from the query
                IWbemClassObject *pclsObj;
                ULONG uReturn = 0;

                while (pEnumerator)
                {
                    HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);

                    if(0 == uReturn)
                    {
                        break;
                    }

                    // find the values of the properties we are interested in
                    tstring name = WmiQueryValue(pclsObj, L"Name");
                    tstring publisher = WmiQueryValue(pclsObj, L"Vendor");
                    tstring version = WmiQueryValue(pclsObj, L"Version");
                    tstring location = WmiQueryValue(pclsObj, L"InstallLocation");

                    if(!name.empty())
                    {
                        tcout << name << endl;
                        tcout << "  - " << publisher << endl;
                        tcout << "  - " << version << endl;
                        tcout << "  - " << location << endl;
                        tcout << endl;
                    }

                    pclsObj->Release();
                }

                pEnumerator->Release();
            }
        }
    }

    // unintializa COM
    ::CoUninitialize();
}

A sample from the output of this WmiEnum() function looks like this:

Java(TM) 6 Update 25
– Oracle
– 6.0.250
– C:\Program Files\Java\jre6\

Java(TM) SE Development Kit 6 Update 25
– Oracle
– 1.6.0.250
– C:\Program Files\Java\jdk1.6.0_25\

Microsoft .NET Framework 4 Client Profile
– Microsoft Corporation
– 4.0.30319
-

Microsoft Sync Framework Services v1.0 SP1 (x86)
– Microsoft Corporation
– 1.0.3010.0
-

Microsoft ASP.NET MVC 2 – Visual Studio 2010 Tools
– Microsoft Corporation
– 2.0.50217.0
-

Adobe Reader X (10.0.1)
– Adobe Systems Incorporated
– 10.0.1
– C:\Program Files\Adobe\Reader 10.0\Reader\

One can notice that the code is relatively long, but most important it is very slow.

MSI API
Two of the MSI API functions can help fetching the list of installed applications:

  • MsiUnumProductsEx: enumerates through one or all the instances of products that are currently advertised or installed (requires Windows Installer 3.0 or newer)
  • MsiGetProductInfoEx: returns product information for advertised and installed products

In order to use these functions you need to include msi.h and link to msi.lib.

In the code below, MsiQueryProperty() is a function that returns the value of product property (as a tstring as defined above) by calling MsiGetProductInfoEx. MsiEnum() is a function that iterates through all the installed applications and prints in the console the name, publisher, version and installation location.

tstring MsiQueryProperty(LPCTSTR szProductCode,
                         LPCTSTR szUserSid,
                         MSIINSTALLCONTEXT dwContext,
                         LPCTSTR szProperty)
{
    tstring value;

    DWORD cchValue = 0;
    UINT ret2 = ::MsiGetProductInfoEx(
        szProductCode,
        szUserSid,
        dwContext,
        szProperty,
        NULL,
        &cchValue);

    if(ret2 == ERROR_SUCCESS)
    {
        cchValue++;
        value.resize(cchValue);

        ret2 = ::MsiGetProductInfoEx(
            szProductCode,
            szUserSid,
            dwContext,
            szProperty,
            (LPTSTR)&value[0],
            &cchValue);
    }

    return value;
}

void MsiEnum()
{
    UINT ret = 0;
    DWORD dwIndex = 0;
    TCHAR szInstalledProductCode[39] = {0};
    TCHAR szSid[128] = {0};
    DWORD cchSid;
    MSIINSTALLCONTEXT dwInstalledContext;

    do
    {
        memset(szInstalledProductCode, 0, sizeof(szInstalledProductCode));
        cchSid = sizeof(szSid)/sizeof(szSid[0]);

        ret = ::MsiEnumProductsEx(
            NULL,           // all the products in the context
            _T("s-1-1-0"),  // i.e.Everyone, all users in the system
            MSIINSTALLCONTEXT_USERMANAGED | MSIINSTALLCONTEXT_USERUNMANAGED | MSIINSTALLCONTEXT_MACHINE,
            dwIndex,
            szInstalledProductCode,
            &dwInstalledContext,
            szSid,
            &cchSid);

        if(ret == ERROR_SUCCESS)
        {
            tstring name = MsiQueryProperty(
                szInstalledProductCode,
                cchSid == 0 ? NULL : szSid,
                dwInstalledContext,
                INSTALLPROPERTY_INSTALLEDPRODUCTNAME);

            tstring publisher = MsiQueryProperty(
                szInstalledProductCode,
                cchSid == 0 ? NULL : szSid,
                dwInstalledContext,
                INSTALLPROPERTY_PUBLISHER);                

            tstring version = MsiQueryProperty(
                szInstalledProductCode,
                cchSid == 0 ? NULL : szSid,
                dwInstalledContext,
                INSTALLPROPERTY_VERSIONSTRING);

            tstring location = MsiQueryProperty(
                szInstalledProductCode,
                cchSid == 0 ? NULL : szSid,
                dwInstalledContext,
                INSTALLPROPERTY_INSTALLLOCATION);            

            tcout << name << endl;
            tcout << "  - " << publisher << endl;
            tcout << "  - " << version << endl;
            tcout << "  - " << location << endl;
            tcout << endl;

            dwIndex++;
        }

    } while(ret == ERROR_SUCCESS);
}

And this is a sample for the WmiEnum() function.

Java(TM) 6 Update 25
– Oracle
– 6.0.250
– C:\Program Files\Java\jre6\

Java(TM) SE Development Kit 6 Update 25
– Oracle
– 1.6.0.250
– C:\Program Files\Java\jdk1.6.0_25\

Microsoft .NET Framework 4 Client Profile
– Microsoft Corporation
– 4.0.30319
-

Microsoft Sync Framework Services v1.0 SP1 (x86)
– Microsoft Corporation
– 1.0.3010.0
-

Microsoft ASP.NET MVC 2 – Visual Studio 2010 Tools
– Microsoft Corporation
– 2.0.50217.0
-

Adobe Reader X (10.0.1)
– Adobe Systems Incorporated
– 10.0.1
– C:\Program Files\Adobe\Reader 10.0\Reader\

Windows Registry
Installed applications are listed in Windows Registry under HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall. The KB247501 article explains the structure of the information under this Registry key. Make sure you read it if you decide to use this approach.

In the code shown below, RegistryQueryValue() is a function that queries the value of a name/value pair in the registry and returns the value as a tstring. RegistryEnum() is a function that prints to the console all the installed application as found in the registry.

tstring RegistryQueryValue(HKEY hKey,
                           LPCTSTR szName)
{
    tstring value;

    DWORD dwType;
    DWORD dwSize = 0;

    if (::RegQueryValueEx(
        hKey,                   // key handle
        szName,                 // item name
        NULL,                   // reserved
        &dwType,                // type of data stored
        NULL,                   // no data buffer
        &dwSize                 // required buffer size
        ) == ERROR_SUCCESS && dwSize > 0)
    {
        value.resize(dwSize);

        ::RegQueryValueEx(
            hKey,                   // key handle
            szName,                 // item name
            NULL,                   // reserved
            &dwType,                // type of data stored
            (LPBYTE)&value[0],      // data buffer
            &dwSize                 // available buffer size
            );
    }

    return value;
}

void RegistryEnum()
{
    HKEY hKey;
    LONG ret = ::RegOpenKeyEx(
        HKEY_LOCAL_MACHINE,     // local machine hive
        _T("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"), // uninstall key
        0,                      // reserved
        KEY_READ,               // desired access
        &hKey                   // handle to the open key
        );

    if(ret != ERROR_SUCCESS)
        return;

    DWORD dwIndex = 0;
    DWORD cbName = 1024;
    TCHAR szSubKeyName[1024];

    while ((ret = ::RegEnumKeyEx(
        hKey,
        dwIndex,
        szSubKeyName,
        &cbName,
        NULL,
        NULL,
        NULL,
        NULL)) != ERROR_NO_MORE_ITEMS)
    {
        if (ret == ERROR_SUCCESS)
        {
            HKEY hItem;
            if (::RegOpenKeyEx(hKey, szSubKeyName, 0, KEY_READ, &hItem) != ERROR_SUCCESS)
                continue;

            tstring name = RegistryQueryValue(hItem, _T("DisplayName"));
            tstring publisher = RegistryQueryValue(hItem, _T("Publisher"));
            tstring version = RegistryQueryValue(hItem, _T("DisplayVersion"));
            tstring location = RegistryQueryValue(hItem, _T("InstallLocation"));

            if(!name.empty())
            {
                tcout << name << endl;
                tcout << "  - " << publisher << endl;
                tcout << "  - " << version << endl;
                tcout << "  - " << location << endl;
                tcout << endl;
            }

            ::RegCloseKey(hItem);
        }
        dwIndex++;
        cbName = 1024;
    }
    ::RegCloseKey(hKey);
}

And a sample output of the RegistryEnum() function:

Java(TM) SE Development Kit 6 Update 25

– Oracle
– 1.6.0.250
– C:\Program Files\Java\jdk1.6.0_25\

Microsoft Visual Studio 2005 Tools for Office Runtime

– Microsoft Corporation
– 8.0.60940.0
-

MSDN Library for Visual Studio 2008 – ENU

– Microsoft
– 9.0.21022
– C:\Program Files\MSDN\MSDN9.0\

Microsoft SQL Server Compact 3.5 SP2 ENU

– Microsoft Corporation
– 3.5.8080.0
– C:\Program Files\Microsoft SQL Server Compact Edition\

Microsoft .NET Framework 4 Client Profile

– Microsoft Corporation
– 4.0.30319
-

, , , , Hits for this post: 8139 .