The MVP Global Summit 2011 took place in Redmond and Bellevue at the beginning of March. This year I attended for the fifth time, and as usual it was a great time. Fellow MVPs, discussions with the Microsoft product groups, parties, everything made it worth it. And this year it was also a little bit special because I was named C++ MVP of the Year, a distinction shared with Kate Gregory. A 3rd C++ MVP, Sheng Jiang, was also named MVP of the Year as top answerer in the MSDN forums. As an MVP of the Year I was invited to attend a dinner held by S. Somasegar, senior vice president of the Developer Division at Microsoft, where I joined the other MVPs of the year in the awarded categories (such as C#, VB, ASP.NET, etc.), but also top figures from Microsoft, such as Scott Guthrie, Jason Zander, Anders Hejlsberg or Scott Hanselman and the Microsoft community leads. This is a picture from the event, showing, from left to right, Sheng Jiang, myself, Diego Dagum – Windows C++ community PM, and Kate Gregory.

Another special moment at this summit was being interviewed by Charles Torre for channel9. He did several interviews with C++ MVPs and these interviews were posted on channel9 recently. Here you can find the original post for the interview with Alon Fliess, Bruno Boucard, Jim Berveridge and myself. We talked mostly about C++, but also the MVP program.

The other interviews that I mentioned can be found here:

Looking forward for the next summit experience.

, , , Hits for this post: 9736 .

Channel9 recently posted a video with the Parallel Computing Concurrency Runtime team talking, mainly, about tasks and continuations, new features to the Parallel Patterns Library. These are already available through the ConcRT Extra’s Sample Pack. You can watch the half hour interview with the team here.

Besides the new stuff they shown, I particularly liked two things that Artur Laksberg said. The first was about the difference between parallelism and concurrency:

Parallelism is doing the same amount of work faster by utilizing multiple cores, multiple processors. Concurrency is understood as doing more work in the same amount of time.

The other one was about threads and tasks:

We want people to stop thinking about threads and start thinking in terms of independent, or not independent, units of work. You have one piece of work, you compose it with another piece of work and you have two tasks, you join together and what you get as a result is another task. And then, concurrency, as somebody said, just happens. It just happens if the runtime decides it’s beneficial for you, that it is safe to execute those two chunks, tasks, in parallel.

Hopefully people will start understanding that threads are obsolete and they should be thinking in tasks.

UPDATE: Microsoft Technical Computing group announced yesterday the availability of a book called Parallel Programming with Microsoft Visual C++: Design patterns for Decomposition, and Coordination on Multicore Architectures, describing six key patterns for data and task parallelism and how to implement them in VC++ using the Parallel Patterns Library and Asynchronous Agents Library, which shipped with Visual Studio 2010. There is also a printed version for the book. You can read more about it on VC++ team’s blog.

, , , , , Hits for this post: 9459 .

I’ve ran recently across this question: how to find (using C++) if a computer is a laptop? That is possible with WMI and many answers (such as this) point to the Win32_SystemEnclosure class. This class has a member called ChassisTypes, which is an array of integers indicating possible chassis types. At least one of them should indicate a laptop. However, there might be several problems with this solution. First, there are several values for “laptops”:

  • 8 – Portable
  • 9 – Laptop
  • 10 – Notebook

Different machines might return different values. And more important, this property might not be defined on all computers. A more reliable solution is explained in this TechNet article Finding Computers That Are Laptops. The solution described there suggests checking for several properties:

  • Win32_SystemEnclosure, ChassisTypes(1)=10.
  • Win32_Battery or Win32_PortableBattery.
  • Win32_PCMCIAController
  • Win32_DriverVXD.Name = “pccard”
  • Win32_ComputerSystem.Manufacturer
  • Win32_ComputerSystem.Model

The following code shows how one can query for the chassis types using C++. Run queries for the other properties to make sure you are running on a laptop.

#define _WIN32_DCOM

#include <iostream>
using namespace std;

#include <comdef.h>
#include <Wbemidl.h>

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

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;
      }
   }
};

int _tmain(int argc, _TCHAR* argv[])
{
   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 1;
   }

   // 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 1;
   }
   else
   {
      WMIQuery query;
      if(query.Initialize())
      {
         IEnumWbemClassObject* pEnumerator = query.Query(_T("SELECT * FROM Win32_SystemEnclosure"));

         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;
               }

               VARIANT vtProp;

               hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0);
               wcout << "Name:    " << vtProp.bstrVal << endl;

               hr = pclsObj->Get(L"ChassisTypes", 0, &vtProp, 0, 0);
               wcout << "Chassis: ";
               SAFEARRAY* parrValues = NULL;

               if (vtProp.vt & VT_ARRAY)
               {
                  if (VT_BYREF & vtProp.vt)
                     parrValues = *vtProp.pparray;
                  else
                     parrValues = vtProp.parray;
               }

               if (parrValues != NULL)
               {
                  SAFEARRAYBOUND arrayBounds[1];
                  arrayBounds[0].lLbound = 0;
                  arrayBounds[0].cElements = 0;

                  SafeArrayGetLBound(parrValues, 1, &arrayBounds[0].lLbound);
                  SafeArrayGetUBound(parrValues, 1, (long*)&arrayBounds[0].cElements);
                  arrayBounds[0].cElements -= arrayBounds[0].lLbound;
                  arrayBounds[0].cElements += 1;

                  if (arrayBounds[0].cElements > 0)
                  {
                     for (ULONG i = 0; i < arrayBounds[0].cElements; i++)
                     {
                        LONG lIndex = (LONG)i;
                        INT item;

                        HRESULT hr = ::SafeArrayGetElement(parrValues, &lIndex, &item);

                        if(SUCCEEDED(hr))
                        {
                           LPCTSTR szType = NULL;
                           switch(item)
                           {
                           case 1: szType = _T("Other"); break;
                           case 2: szType = _T("Unknown"); break;
                           case 3: szType = _T("Desktop"); break;
                           case 4: szType = _T("Low Profile Desktop"); break;
                           case 5: szType = _T("Pizza Box"); break;
                           case 6: szType = _T("Mini Tower"); break;
                           case 7: szType = _T("Tower"); break;
                           case 8: szType = _T("Portable"); break;
                           case 9: szType = _T("Laptop"); break;
                           case 10:szType = _T("Notebook"); break;
                           case 11:szType = _T("Hand Held"); break;
                           case 12:szType = _T("Docking Station"); break;
                           case 13:szType = _T("All in One"); break;
                           case 14:szType = _T("Sub Notebook"); break;
                           case 15:szType = _T("Space-Saving"); break;
                           case 16:szType = _T("Lunch Box"); break;
                           case 17:szType = _T("Main System Chassis"); break;
                           case 18:szType = _T("Expansion Chassis"); break;
                           case 19:szType = _T("SubChassis"); break;
                           case 20:szType = _T("Bus Expansion Chassis"); break;
                           case 21:szType = _T("Peripheral Chassis"); break;
                           case 22:szType = _T("Storage Chassis"); break;
                           case 23:szType = _T("Rack Mount Chassis"); break;
                           case 24:szType = _T("Sealed-Case PC"); break;
                           }
                           wcout << szType;
                           if(i+1 < arrayBounds[0].cElements)
                              wcout << ", ";
                        }
                     }

                     wcout << endl;
                  }
               }

               VariantClear(&vtProp);

               pclsObj->Release();
            }

            pEnumerator->Release();
         }
      }
   }

   ::CoUninitialize();

   return 0;
}

On my laptop, the program output was:

Name: System Enclosure
Chassis: Notebook

, , , Hits for this post: 12094 .

It is possible to register both 32-bit and 64-bit versions of the same COM server on 64-bit machine. This leads to several questions such as how are they registered and which one of the two is used. I will try to answer them below. But first, let’s start with an example.

Example
Let’s say we have the a simple COM local server called COM3264Server.exe. There is just one interface called ICoCOM3264Server. Here is the IDL file:

[
	object,
	uuid(733C70A7-F7EC-4C15-85D2-5CDB14F4110B),
	dual,
	nonextensible,
	pointer_default(unique)
]
interface ICoCOM3264Server : IDispatch{
   [id(1), helpstring("Says hello")] HRESULT SayHello(void);
};
[
	uuid(2F25FC66-2380-42FD-8476-8B5917FB1BF1),
	version(1.0),
]
library COM3264ServerLib
{
	importlib("stdole2.tlb");
	[
		uuid(9268A299-E817-4C5D-8627-C2582B66F16D)
	]
	coclass CoCOM3264Server
	{
		[default] interface ICoCOM3264Server;
	};
};

The implementation of the method SayHello() is straight forward; it just displays a message box with a text that varies between the two architectures, x64 and x86.

STDMETHODIMP CCoCOM3264Server::SayHello(void)
{
#ifdef _WIN64
   ::MessageBox(NULL, _T("Hello from 64-bit COM server!"), _T("COM3264Server"), MB_OK);
#else
   ::MessageBox(NULL, _T("Hello from 32-bit COM server!"), _T("COM3264Server"), MB_OK);
#endif

   return S_OK;
}

Registry
When you register the COM server, the 32-bit and 64-bit versions are registered in different parts of the registry. On 64-bit machine, the registry has two views (or modes):

  • a native view, for 64-bit application; (e.g. registry path for CLSIDs is HKEY_CLASSES_ROOT\CLSID\)
  • a WOW64 view, which enables redirections for 32-bit applications, a process transparent to the user (e.g. registry path for CLSIDs is HKEY_CLASSES_ROOT\Wow6432Node\CLSID\)

Here is the Registry registration of the (native) 64-bit COM server (notice the registry key in the status bar of the editor, and the path to the server executable).

On, the other hand, the 32-bit COM server is registered under the Wow6432 node.

So if both versions are registered in Windows Registry, which one is picked? Well, both the server and the client can specify which architecture to use:

  • the COM server can do this via the PreferredServerBitness Registry value
  • the client can do this using one of the flags CLSCTX_ACTIVATE_32_BIT_SERVER and CLSCTX_ACTIVATE_64_BIT_SERVER, which overrides the server preference

If neither the client nor the server specifies a preference, then:

  • If the computer that hosts the server is running Windows Server 2003 with Service Pack 1 (SP1) or a later system, then COM will try to match the server architecture to the client architecture. In other words, for a 32-bit client, COM will activate a 32-bit server if available; otherwise it will activate a 64-bit version of the server. For a 64-bit client, COM will activate a 64-bit server if available; otherwise it will activate a 32-bit server.
  • If the computer that hosts the server is running Windows XP or Windows Server 2003 without SP1 or later installed, then COM will prefer a 64-bit version of the server if available; otherwise it will activate a 32-bit version of the server.

Server Preference
The server can specify its preferred architecture in the PreferredServerBitness value under AppId (available only on 64-bit Windows). This integer value can be:

  • 1: Match the server architecture to the client architecture. For example, if the client is 32-bit, use a 32-bit version of the server, if it is available. If not, the client’s activation request will fail.
  • 2: Use a 32-bit version of the server. If one does not exist, the client’s activation request will fail.
  • 3: Use a 64-bit version of the server. If one does not exist, the client’s activation request will fail.

Here is the value set in Registry to specify the 64-bit architecture.

When you run the client, it launches the 64-bit version and in my example the following window pops-up:

If I change the value to indicate the 32-bit architecture, the other COM server is launched and the displayed message is:

Client Preference
The client code I used so far looked like this:

   ICoCOM3264Server* pServer;

   HRESULT hr = ::CoCreateInstance(
      CLSID_CoCOM3264Server,
      NULL,
      CLSCTX_LOCAL_SERVER|CLSCTX_REMOTE_SERVER,
      IID_ICoCOM3264Server,
      (void**)&pServer);

   if(SUCCEEDED(hr))
   {
      pServer->SayHello();

      pServer->Release();
   }

However, the 64-bit version of Windows added new flags to the CLSCTX enumeration.

  • CLSCTX_ACTIVATE_32_BIT_SERVER: used to activate or connect to a 32-bit version of the server; fail if one is not registered.
  • CLSCTX_ACTIVATE_64_BIT_SERVER: used to activate or connect to a 64 bit version of the server; fail if one is not registered.

As I mentioned earlier, if the client uses one of these flags, it overrides the server preference (specified via the PreferredServerBitness Registry value).

In the following example, the client requests the 64-bit COM server:

   HRESULT hr = ::CoCreateInstance(
      CLSID_CoCOM3264Server,
      NULL,
      CLSCTX_LOCAL_SERVER|CLSCTX_REMOTE_SERVER|CLSCTX_ACTIVATE_64_BIT_SERVER,
      IID_ICoCOM3264Server,
      (void**)&pServer);

And if you run it, no matter what the server specified, the 64-bit COM server is launched.

To read more about the subject see the MSDN links above.

, , , Hits for this post: 13613 .

Two days ago I posted a simple implementation of a game of colors. Though it was intended only as an exercise, someone has criticizes the use of an int** to hold the grid information, mainly for two reasons:

  • the footprint on 64-bit platforms can get nasty
  • the explicitly allocated memory, instead of using a std::vector

So this is the code:

int** m_pCells; 

void Create()
{
   m_pCells = new int*[m_nSize];
   for(int i = 0; i < m_nSize; ++i)
      m_pCells[i] = new int[m_nSize];
}

Let’s see how much memory it takes. The total size should be:

totalsize = sizeof(m_pCells) + sizeof(m_pCells[0]) * m_nSize + m_nSize * m_nSize * sizeof(int);

On 32-bit platforms, the size of a pointer is the same with the size of int and is 4 bytes. For the maximum size allowed for my grid, which is 50, the total size in bytes for the grid is: 4 + 4*50 + 50*50*4 = 10204.

On 64-bit platforms, the size of a pointer is 8 bytes, but the size of int is still 4 bytes. So for a grid with 50 rows and columns it needs: 8 + 8*50 + 50*50*4 = 10408 bytes. That’s a 2% increase of required memory.

The memory footprint was the last thing I had in mind when I wrote this simple exercise. Well, of course there is a way to require only 4 more bytes on 64-bit platforms. And that is using an int* allocating m_nSize*m_nSize elements.

int* m_pCells;

void Create()
{
   m_pCells = new int[m_nSize * m_nSize];
}

void Destroy()
{
   delete [] m_pCells;
   m_pCells = NULL;
}

With this implementation, when you need to access the element at row i and column j, you have to use m_pCells[i * m_nSize + j].

As for the second argument, that explicitly using operator new[] to allocate memory instead of using a vector of vectors, well, what could I say? Sure, why not. Different people use different programming styles. As long as all implementation are correct and achieve the same goal with similar performance, I guess everyone is entitle to code as he/she wants. But if we go back to the memory footprint, I would also guess that the use of vectors would take more memory than pointers to int, because the size of a vector is several times the size of a pointer. But I wouldn’t say that’s an important issue here.

Anyway, these arguments remember me the joke (or maybe it’s serious) about the rules of optimization:

  1. Don’t optimize.
  2. Don’t optimize yet (for experts only).

(Of course there are super experts that can ignore these rules.)

, , , , Hits for this post: 6940 .

Some of the important changs in Visual Studio 2010 in regard to VC++ are represented by the support in the C++ compiler of some of the features already approved for the new C++ standard, so far called C++0x. In this post I will give a short overview on then.

static_assert

I already wrote a post about this feature. At that time I considered it rather a niche feature. However, this looks much powerful in conjunction with the type traits classes from TR1.

static_assert checks if an expression is true at compile time. If the expression if false a custom error message is displayed and the compilation fails. If the expression is true the declaration has no effect.

In the following example I create a comparison template function, that is used later to compare values.

template < typename T >
bool CompareNumbers(T v1, T v2)
{
   return v1 > v2;
}

int main()
{
   bool ret1 = CompareNumbers(1, 20);
   bool ret2 = CompareNumbers("b", "a");

   return 0;
}

I want this function to be used only for integral types (the reason doesn’t matter) and I’d like the compiler to issue an error when used with any other type. Adding a static_assert check will generate a compilation error for the second call to the function, when passing strings.

#include < type_traits >

template < typename T >
bool CompareNumbers(T v1, T v2)
{
   static_assert(std::tr1::is_integral< T >::value, "Type is not numeric");
   return v1 > v2;
}
1>d:\marius\vc++\cpp0x\cpp0x.cpp(62): error C2338: Type is not numeric
1>          d:\marius\vc++\trainnings\cpp0x\cpp0x.cpp(75) : see reference to function template instantiation 'bool CompareNumbers(T,T)' being compiled
1>          with
1>          [
1>              T=const char *
1>          ]

auto

If you are familiar with C#, this is the C++ equivalent of var. The keyword is used to deduce the type of a declared variable from its initialization expression. The initialization expression can be an assignment, direct initialization or operator new expression. It must be noted that the auto keyword is just a placeholder, not a type, and cannot be used with sizeof or typeid.

auto i = 13;        // i is int
auto s = "marius";  // s is std::string
auto p = new foo(); // p is foo*

vector< int > numbers;
generate_n(back_inserter(numbers), 10, rand);
for(auto it = numbers.begin(); it != numbers.end(); ++it)
{
   cout << *it << endl;
}

lambda expressions

I already wrote about lambdas, but I will give a short overview again. Again, if you are familiar with C# and .NET, this is the same concept as in .NET.

A lambda functions is a function object whose type is implementation dependent; its type name is only available to the compiler. The lambda expression is composed of several parts:

  • lambda_introducer: this is the part that tells the compiler a lambda function is following. Inside the angled brackets a capture-list can be provided; this is used for capturing variables from the scope in which the lambda is created.
  • lambda-parameter-declaration: used for specifying the parameters of the lambda function.
  • lambda-return-type-clause: used for indicating the type returned by the lambda function. This is optional, because most of the time the compiler can infer the type. There are cases when this is not possible and then the type must be specified. For the example above, the return type (-> bool) is not necessary.
  • compound-statement: this is the body of the lambda.
vector<int> numbers;
generate_n(back_inserter(numbers), 10, rand);

for_each(numbers.begin(), numbers.end(), [](int n) {cout << n << endl;});

Here [] is the lambda introducer, (int n) is the lambda parameter declaration, and {cout << n << endl;} is the lambda compound statement. There is no return type clause, because that is auto inferred by the compiler. There are cases when the compiler cannot deduce the return value and then it must be specified explicitly. A lambda expression is a syntactic shortcut for a functor. The code above is equivalent to:

class functor_lambda
{
public:
   void operator()(int n) const
   {
      cout << n << endl;
   }
};

vector<int> numbers;
generate_n(back_inserter(numbers), 10, rand);

for_each(numbers.begin(), numbers.end(), functor_lambda());

Lambdas can capture variables from their scope by value, reference or both in any combination. In the example above, there was no value captured. This is a stateless lambda. On the other hand, a lambda that captures variables is said to have a state.

rvalue references

Stephan T. Lavavej wrote the ultimate guide to rvalue references. There is nothing more that can be said that is not already there. I strongly suggest you read his article to familiarize with this concept.

rvalue references are used to hold a reference to a rvalue or lvalue expression, and are introduced with &&. They enable the implementation of move semantics and perfect forwarding.

Move semantics enable transferring resources from one temporary object to another. This is possible because temporary objects (i.e. rvalues) are not referred anywhere else outside the expression in which they live. To implement move semantics you have to provide a move constructor and optionally a move assignment operator. The Standard Template Library was changed to take advantage of this feature. A classic example for the move semantics is represented by operation with sequences like vector or list. A vector allocates memory for a given number of objects. You can add elements to it and no re-allocation is done until the full capacity is reached. But when that happens, the vector has to reallocate memory. In this case it allocates a new larger chunk, copies all the existing content, and then releases the pervious memory. When an insertion operation needs to copy one element several things happen: a new element is created, its copy constructor is called, and then the old element is destroyed. With moves semantics, the allocation of a new element and its copy is no longer necessary, the existing element can be directly moved.

A second scenario where rvalue references are helpful is the perfect forwarding. The forwarding problem occurs when a generic function takes references as parameters and then needs to forward these parameters to another function. If a generic function takes a parameter of type const T& and needs to call a function that takes T&, it can’t do that. So you need an overloaded generic function. What rvalue references enable is having one single generic function that takes arbitrary arguments and then forwards them to another function.

decltype operator

This is used to yield the type of an expression. Its primary purpose is for generic programming, in conjunction with auto, for return types of generic functions where the type depends on the arguments of the function. Here are several examples:

double d = 42.0;     // decltype(i) yields double
const int&& f();     // decltype(f()) yields const int&&
struct foo {int i;}; // decltype(f.i) yields int (f being an object of type foo)

It can be used together with auto to declare late specified return type, with the alternative function declaration syntax, which is (terms in squared brackets indicate optional parts)

auto function_name([parameters]) [const] [volatile] -> decltype(expression) [throw] {function_body};

In general, the expression use with decltype here should match the expression used in the return statement.

struct Liters
{
   double value;
   explicit Liters(double val):value(val){}
};

struct Gallons
{
   double value;
   explicit Gallons(double val):value(val){}
};

ostream& operator<<(ostream& os, const Liters& l)
{
   os << l.value << "l";
   return os;
}

ostream& operator<<(ostream& os, const Gallons& g)
{
   os << g.value << "gal";
   return os;
}

Liters operator+(const Liters& l1, const Liters& l2)
{
   return Liters(l1.value + l2.value);
}

Gallons operator+(const Gallons& g1, const Gallons& g2)
{
   return Gallons(g1.value + g2.value);
}

Liters operator+(const Liters& l, const Gallons& g)
{
   return Liters(l.value + g.value*3.785);
}

Gallons operator+(const Gallons& g, const Liters& l)
{
   return Gallons(g.value + l.value*0.264);
}

template <typename T1, typename T2>
auto Plus(T1&& v1, T2&& v2) -> decltype(forward< T1 >(v1) + forward< T2 >(v2))
{
   return forward< T1 >(v1) + forward< T2 >(v2);
}

int main()
{
   cout << Plus(l1, l2) << endl;
   cout << Plus(g1, g2) << endl;
   cout << Plus(l1, g1) << endl;
   cout << Plus(g2, l2) << endl;

   return 0;
}

The result of the execution is:

15l
30gal
42.85l
22.64gal

When function Plus is called with arguments of the same type, the result is that type. But when the arguments differ, the resulting type is also different. In this example, when the first argument is Liters and second is Gallons, the result type must be Liters and the opposite. It is possible to do this without decltype, but the solution requires explicit specification of the resulting type.

template <typename T, typename T1, typename T2>
T Plus(T1&& v1, T2&& v2)
{
   return forward< T1 >(v1) + forward< T2 >(v2);
}

int main()
{
   cout << Plus<Liters>(l1, l2) << endl;
   cout << Plus<Gallons>(g1, g2) << endl;
   cout << Plus<Liters>(l1, g1) << endl;
   cout << Plus<Gallons>(g2, l2) << endl;

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

I recently found a piece of code that can be summarized by the following sample:

interface I
{
   void F1();
   void F2();
}

class X
{
   public void F2() { Console.WriteLine("F2"); }
}

class A : X, I
{
   public void F1() { Console.WriteLine("F1"); }
}

As you can see there is an interface I that has two methods, F1 and F2. A is derived from X, that has a method F2, and also implements I, but only contains F1. I was puzzled at first, because I was expecting that A was explictitly implementing all the methods defined in the interface I. But F2 was implemented in X, its base class. After thinking a little bit it all become clear. This was a normal behavior of the compiler.

When a class A implements an interface I it guarantees that it supports (implements) the entire contract that the interface defines. But it does not assert that it will explicitly implement all the interface members within its explicit definition. I’m stressing on the explicit word here, because A extends (is derived from) X. That means A is an X. Everything that X exposes (i.e. what is visible to its derived classes) is part of A too.

In our case, F2, implemented in X, is also available to A, because A is an X. Since both F1 and F2 are members of A, then it means A fully implements I, which makes the code compile just fine.

How is this helpful? Suppose you have several interfaces that all define one ore several members with the same meaning.

interface I1
{
  void F1();
  void F2();
  int ErrorCode { get; }
}

interface I2
{
  void G1();
  void G2();
  int ErrorCode { get; }
}

interface I3
{
  void H1();
  int ErrorCode { get; }
}

Instead of providing the same implementation several times, like in the following code, you can have only one implementation for the common functionality.

class A : I1
{
  private int m_errorCode;

  public void F1() {}
  public void F2() {}
  public int ErrorCode { get {return m_errorCode;} }
}

class B : I2
{
  private int m_errorCode;

  public void G1() {}
  public void G2() {}
  public int ErrorCode { get {return m_errorCode;} }
}

class C : I3
{
  private int m_errorCode;

  public void H1() {}
  public int ErrorCode { get {return m_errorCode;} }
}

We can create one class that provides the implementation for ErrorCode and let the others extend it and implement the corresponding interface.

class X
{
  protected int m_errorCode;

  public int ErrorCode { get {return m_errorCode;} }
}

class A : X, I1
{
  public void F1() {}
  public void F2() {}
}

class B : X, I2
{
  public void G1() {}
  public void G2() {}
}

class C : X, I3
{
  public void H1() {}
}

, , , Hits for this post: 10811 .

.NET provides two classes for image transformations: Matrix, used for geometric transformations, and ColorMatrix, used for color transformations.

One of such color transformations is inverting or negating. This means subtracting each color component from 255. Black (0,0,0) becomes White (255, 255, 255), and Green (0, 255, 0) becomes Magenta (255, 0, 255).

You can find many examples on the web that look like this:

public Bitmap Transform(Bitmap source)
{
    //create a blank bitmap the same size as original
    Bitmap newBitmap = new Bitmap(source.Width, source.Height);

    //get a graphics object from the new image
    Graphics g = Graphics.FromImage(newBitmap);

    // create the negative color matrix
    ColorMatrix colorMatrix = new ColorMatrix();
    colorMatrix.Matrix00 = colorMatrix.Matrix11 = colorMatrix.Matrix22 = -1f;
    colorMatrix.Matrix33 = colorMatrix.Matrix44 = 1f;

    // create some image attributes
    ImageAttributes attributes = new ImageAttributes();

    attributes.SetColorMatrix(colorMatrix);

    g.DrawImage(source, new Rectangle(0, 0, source.Width, source.Height),
                0, 0, source.Width, source.Height, GraphicsUnit.Pixel, attributes);

    //dispose the Graphics object
    g.Dispose();

    return newBitmap;
}

Using this code one can get a negative image.

Original image

Original image

Negative image

Negative image

This runs fine on Windows XP. But when I ran it on Windows 7, I was getting only a black image. All the pixels were ARGB(255, 0, 0, 0). This was how it looked:

Incorrectly transformed image

Incorrectly transformed image

I was surprised to learn that it worked on Windows XP, but not on Windows 7. I don’t have Windows Vista to test but I guess it’s the same as with Windows 7. I thought it must be something in the GDI+ library, because building with .NET 3.5 SP1 or 4.0 Beta 2 didn’t change a thing.

After trying different things, I figured out what the problem was: the color matrix was incorrect. It must be defined like this:

ColorMatrix colorMatrix = new ColorMatrix(
   new float[][]
   {
      new float[] {-1, 0, 0, 0, 0},
      new float[] {0, -1, 0, 0, 0},
      new float[] {0, 0, -1, 0, 0},
      new float[] {0, 0, 0, 1, 0},
      new float[] {1, 1, 1, 0, 1}
   });

With this change the Transform function produces a correct negative image, regardless the operating system or the .NET framework version.

However, what I don’t know yet, is why it worked on Windows XP. The only conclusion I can draw is that the GDI+ implementation has a fault there, that was later corrected. That’s why an incorrect color matrix produced a correct transformation on Windows XP.

, , , , Hits for this post: 11433 .

.NET 3.0 provides some support for working with ZIP files. However, it has an important drawback: it only works for packages that are conformant to the Open Packaging Convention standard. Most of the ZIP files are not. Codeplex features a library called DotNetZip that provides support for packing and unpacking in C#, VB.NET or any other .NET language, but also any COM environment, including Javascript, VBSCript, VB6, VBA, PHP, Perl. In addition to the basic packing and unpacking operations, it supports password protection, UNICODE filenames, ZIP64 and AES encryption, comment, and others. Here are some simple samples.

Creating a ZIP file:

      public static void PackZip(string source, string targetzip)
      {
         if(File.Exists(source))
         {
            PackFile(source, targetzip);
         }
         else if(Directory.Exists(source))
         {
            PackFolder(source, targetzip);
         }
         else
         {
            Console.WriteLine("Source does not exists!");
         }
      }

      public static void PackFile(string file, string targetzip)
      {
         using (ZipFile zipfile = new ZipFile())
         {
            zipfile.AddFile(file, String.Empty);
            zipfile.Save(targetzip);
         }
      }

      public static void PackFolder(string folder, string targetzip)
      {
         using (ZipFile zipfile = new ZipFile())
         {
            zipfile.AddDirectory(folder);
            zipfile.Save(targetzip);
         }
      }

Unpacking to a target folder:

      public static void UnpackZip(string zippath, string targetdir)
      {
         if(ZipFile.IsZipFile(zippath))
         {
            using (ZipFile zipfile = ZipFile.Read(zippath))
            {
               foreach (ZipEntry zipentry in zipfile)
               {
                  try
                  {
                     zipentry.Extract(targetdir, ExtractExistingFileAction.OverwriteSilently);
                  }
                  catch (ZipException ex)
                  {
                     if (ex.InnerException == null)
                     {
                        Console.WriteLine(ex.Message);
                     }
                     else
                     {
                        Console.WriteLine("{0}: {1}", ex.Message, ex.InnerException.Message);
                     }
                  }
               }
            }
         }
         else
         {
            Console.WriteLine("Not a zip file!");
         }
      }

Display the content of a ZIP archive:

      public static void ShowZipContent(string zippath)
      {
         if(ZipFile.IsZipFile(zippath))
         {
            using(ZipFile zipfile = ZipFile.Read(zippath))
            {
               foreach(ZipEntry zipentry in zipfile)
               {
                  Console.WriteLine("{0}", zipentry.FileName);
               }
            }
         }
         else
         {
            Console.WriteLine("Not a zip file!");
         }
      }

You can find many more examples on Codeplex: C# and VB.NET.

, , , , Hits for this post: 9355 .

Sometimes you want to customize a file dialog, maybe to provide a preview for images or files in general. Fortunately, the common file dialog can be easily extended to achieve this. I will explain in this post how to do that.

There are several things one needs to do to extend the file dialog. First step is to create a dialog template. There are several properties (styles that have to be set on this template).

  • WS_CHILD, necessary because this dialog is a child of the original file dialog
  • WS_CLIPSIBLINGS, required so that the child dialog box does not paint over the original file dialog
  • DS_3DLOOK, so that consistency of the look of the controls in the child dialog and the original dialog is preserved
  • DS_CONTROL, allows the user to navigate through the controls of the customized dialog with TAB or navigation keys

When using the template, the following should be done for the OPENFILENAME structure:

  • if the template is a resource in an application or DLL library, then:
    • Flags should contain OFN_ENABLETEMPLATE
    • hInstance must point to the module containing the resource
    • lpTemplateName should contain the template name
  • if the template is already in memory then
    • Flags should contain OFN_ENABLETEMPLATEHANDLE
    • hInstance member must identify the memory object that contains the template

The following code shows how to display a customized file dialog with a template with the ID set to “DIALOG_PREVIEW”:

	CFileDialog fileDialog(TRUE, NULL, NULL, OFN_HIDEREADONLY, _T("All files (*.*)|*.*||"));

	fileDialog.m_ofn.Flags |= OFN_ENABLETEMPLATE;
	fileDialog.m_ofn.hInstance = AfxGetInstanceHandle();
	fileDialog.m_ofn.lpTemplateName = _T("DIALOG_PREVIEW");

	fileDialog.DoModal();

The common file dialog is expanded on the sides so that the new controls have enough space. There are several rules that apply to this repositioning. I will explain them and exemplify with some images.

  • By default all the controls from the custom dialog are placed below the controls from the original file dialog. The following images show a simple dialog template with a check box and a static control (for a preview). By default, these controls are placed at the bottom of the dialog.
    Simple dialog template

    Simple dialog template


    Custom dialog with preview controls placed at the bottom

    Custom dialog with preview controls placed at the bottom

  • If the dialog template contains a static control with the id stc32 (defined in DLG.h), the controls will be positioned relative to this control (with the original dialog being displayed in its placed, in the original size).
    • all controls above and to the left of stc32 are positioned above and to the left of the original controls, with the same amount.
      Template with stc32 control position on the right and middle

      Template with stc32 control position on the right and middle


      Custom File Fialog with Preview controls on the top left

      Custom File Fialog with Preview controls on the top left

    • all controls below and to the right of stc32 are positioned below and to the right of the original controls.
      Template with stc32 control position on the left and middle

      Template with stc32 control position on the left and middle


      Custom File Fialog with Preview controls on the top and on the right

      Custom File Fialog with Preview controls on the top and on the right

Base on that, if you want to place the preview controls on the right (as I would do), you’d have to place the stc32 control on the left of all the controls from your template. In other words, the template needs to look like this:

Template with stc32 on the left of all controls

Template with stc32 on the left of all controls

The resulting file dialog would look like this:

Custom File Dialog with Preview Controls on the right side

Custom File Dialog with Preview Controls on the right side

Note: In the above images the stc32 control had the border style set one one hand to make the control visible on the dialog template and on the other hand to have the the original file dialog controls more visible within the resulting file dialog. You wouldn’t do that with an actual file dialog.

As you could see from the sample code above, it’s very simple to extend the common file dialog. Of course, the part I haven’t shown so far is how to make use of these additional controls. But that is very simple. You just derive CFileDialog, add handlers for the new controls, implement all the logic you want, and instead of instantiating a CFileDialog object you instantiate an object of your derived class. In a following post I will explain how you can add preview functionality to such a custom file dialog.

You can read more about this topic in the following articles:

, , , , Hits for this post: 18962 .