Click here to Skip to main content
15,883,883 members
Articles / Mobile Apps

Generating GUIDs on the Pocket PC

Rate me:
Please Sign up or sign in to vote.
4.94/5 (10 votes)
19 Jan 2004CPOL5 min read 67.1K   150   32  
Generating GUIDs on the Pocket PC

This article has been provided courtesy of MSDN.

Summary

The Guid.NewGuid method generates new GUIDs (globally unique identifier) but is not supported in the Microsoft .NET Compact Framework. Learn how to generate Guid objects that follow the documented GUID specifications for Pocket PC applications. (11 printed pages)

Contents

Overview

The .NET Compact Framework team constantly made tradeoffs between the framework footprint size, performance, and implementation time. The full .NET Framework Guid.NewGuid method calls the Windows API function CoCreateGuid that calls UuidCreate to generate globally unique 128-bit numbers. Unfortunately, these functions are not supported on the Pocket PC, so the Guid.NewGuid method was not implemented for the .NET Compact Framework.

It turns out that it's easy to write a custom implementation of the Guid.NewGuid method. The following shows a test application that generates GUIDs on the Pocket PC. It uses a custom class called PocketGuid, that uses the same algorithm as desktop GUIDs and is discussed in more detail later in this paper.

Figure 1. Generating GUIDs on the Pocket PC

The GUID Format

GUIDs consist of random numbers grouped into several sections: timestamp, clock sequence and node. The different sections for the GUID 8743428c-ef91-4d05-9e7c-4a2e856e813a are shown in the following table.

Table 1. Different sections of a GUID.

GUID SectionComments
8743428cLow field of the timestamp
ef91Middle field of the timestamp
4d05High field of the timestamp with multiplexed version number
9eHigh field of the clock sequence with multiplexed variant type
7cLow field of the clock sequence
4a2e856e813aSpatially unique node identifier

Variant

One to three bits of the clock sequence section are used to define the variant, or layout, of the GUID. Windows and the PocketGuid class generate variant type 2 GUIDs.

Table 2. Variant information stored in GUIDs

Upper 3 Bits of Clock SequenceVariant TypeComments
0 - -0Reserved for NCS (Network Computing System) backward compatibility
1 0 -2Standard format
1 1 06Reserved for Microsoft Corporation backward compatibility
1 1 17Reserved for future definition

Version

The upper four bits of the timestamp section contain the GUID's version that specifies the content of each section. Before Windows 2000, the CoCreateGuid function generated version 1 GUIDs. With Windows 2000, Microsoft switched to version 4 GUIDs, since embedding the MAC address was viewed as a security risk. The PocketGuid class also generates version 4 GUIDs.

Table 3. Version information stored in GUIDs

Upper 4 Bits of TimestampVersionComments
0 0 0 11Time-based version
Uses timestamp, clock sequence, and MAC network card address
0 0 1 02Reserved
0 0 1 13Name-based version
Constructs values from a name for all sections
0 1 0 04Random version
Use random numbers for all sections

The following sites contain more information on the GUID specification:

Generating Random Numbers

The PocketGuid class uses the CryptGenRandom API function to generate random numbers. The first argument to the function is a CSP (cryptographic service provider) handle, that is created by calling CryptAcquireContext, and is released with the CryptReleaseContext function.

The CryptGenRandom function fills a buffer with cryptographically-random bytes that are more random (less predictable and more evenly distributed) than using the System.Random class. Entropy, the measure of uncertainty, is generated for the CryptGenRandom function from the following sources on Windows CE:

  • Thread and kernel switches
  • The current process identifier
  • The current thread identifier
  • Ticks since boot
  • Current time
  • Memory information
  • Object store statistics

The PocketGuid Class

Now that we know the GUID format (128 bit random number with multiplexed variant and version bits), and how to generate random numbers (use crypto API functions), it's very easy to implement the NewGuid method. The code for the PocketGuid class is shown below in C# and VB.NET.

The class contains two private enums, GuidVariant and GuidVersion, that list the different variant and version options. The private classes Const and WinApi contain constants used in the class and the DllImport statements for the crypto API functions. The static method PocketGuid.NewGuid does the following:

  • Calls CryptAcquireContext to get a crypto provider handle
  • Calls CryptGenRandom to generate a 128 bit cryptographically random number
  • Sets the variant and version bits
  • Creates a new System.Guid object and passes the byte array to the constructor
  • Calls CryptReleaseContext to release the crypto provider handle
  • Returns a new System.Guid object if successful, otherwise a SystemException is thrown

C#

C#
using System;
using System.Runtime.InteropServices;

namespace PocketGuid
{
   /// <summary>
   /// Generate GUIDs on the .NET Compact Framework.
   /// </summary>
   public class PocketGuid
   {
      // guid variant types
      private enum GuidVariant
      {
         ReservedNCS = 0x00,
         Standard = 0x02,
         ReservedMicrosoft = 0x06,
         ReservedFuture = 0x07
      }

      // guid version types
      private enum GuidVersion
      {
         TimeBased = 0x01,
         Reserved = 0x02,
         NameBased = 0x03,
         Random = 0x04
      }
         
      // constants that are used in the class
      private class Const
      {
         // number of bytes in guid
         public const int ByteArraySize = 16;
         
         // multiplex variant info
         public const int VariantByte = 8;
         public const int VariantByteMask = 0x3f;
         public const int VariantByteShift = 6;

         // multiplex version info
         public const int VersionByte = 7;
         public const int VersionByteMask = 0x0f;
         public const int VersionByteShift = 4;
      }

      // imports for the crypto api functions
      private class WinApi
      {
         public const uint PROV_RSA_FULL = 1;
         public const uint CRYPT_VERIFYCONTEXT = 0xf0000000;

         [DllImport("coredll.dll")] 
         public static extern bool CryptAcquireContext(
            ref IntPtr phProv, string pszContainer, string pszProvider,
            uint dwProvType, uint dwFlags);

         [DllImport("coredll.dll")] 
         public static extern bool CryptReleaseContext( 
            IntPtr hProv, uint dwFlags);

         [DllImport("coredll.dll")] 
         public static extern bool CryptGenRandom(
            IntPtr hProv, int dwLen, byte[] pbBuffer);
      }
      
      // all static methods
      private PocketGuid()
      {
      }
      
      /// <summary>
      /// Return a new System.Guid object.
      /// </summary>
      public static Guid NewGuid()
      {
         IntPtr hCryptProv = IntPtr.Zero;
         Guid guid = Guid.Empty;
         
         try
         {
            // holds random bits for guid
            byte[] bits = new byte[Const.ByteArraySize];

            // get crypto provider handle
            if (!WinApi.CryptAcquireContext(ref hCryptProv, null, null, 
               WinApi.PROV_RSA_FULL, WinApi.CRYPT_VERIFYCONTEXT))
            {
               throw new SystemException(
               "Failed to acquire cryptography handle.");
            }
      
            // generate a 128 bit (16 byte) cryptographically random number
            if (!WinApi.CryptGenRandom(hCryptProv, bits.Length, bits))
            {
               throw new SystemException(
               "Failed to generate cryptography random bytes.");
            }
            
            // set the variant
            bits[Const.VariantByte] &= Const.VariantByteMask;
            bits[Const.VariantByte] |= 
               ((int)GuidVariant.Standard << Const.VariantByteShift);

            // set the version
            bits[Const.VersionByte] &= Const.VersionByteMask;
            bits[Const.VersionByte] |= 
               ((int)GuidVersion.Random << Const.VersionByteShift);
         
            // create the new System.Guid object
            guid = new Guid(bits);
         }
         finally
         {
            // release the crypto provider handle
            if (hCryptProv != IntPtr.Zero)
               WinApi.CryptReleaseContext(hCryptProv, 0);
         }
         
         return guid;
      }
   }
}

VB.NET

VB.NET
Imports System.Runtime.InteropServices

'
' Generate GUIDs on  the  .NET Compact Framework.
'
Public Class PocketGuid

   ' guid variant types
   Private Enum GuidVariant
      ReservedNCS = &H0
      Standard = &H2
      ReservedMicrosoft = &H6
      ReservedFuture = &H7
   End Enum

   ' guid version types
   Private Enum GuidVersion
      TimeBased = &H1
      Reserved = &H2
      NameBased = &H3
      Random = &H4
   End Enum

   ' constants  that are used in the class
   Private Class ConstValues
      ' number of  bytes in guid
      Public Const ByteArraySize As Integer = 16

      ' multiplex  variant  info
      Public Const VariantByte As Integer = 8
      Public Const VariantByteMask As Integer = &H3F
      Public Const VariantByteShift As Integer = 6

      ' multiplex  version  info
      Public Const VersionByte As Integer = 7
      Public Const VersionByteMask As Integer = &HF
      Public Const VersionByteShift As Integer = 4
   End Class

   ' imports for the crypto api functions
   Private Class WinApi
      Public Const PROV_RSA_FULL As Integer = 1
      Public Const CRYPT_VERIFYCONTEXT As Integer = &HF0000000

      <DllImport("coredll.dll")> _
      Public Shared Function CryptAcquireContext( _
         ByRef phProv As IntPtr, ByVal pszContainer As String, _
         ByVal pszProvider As String, ByVal dwProvType As Integer, _
         ByVal dwFlags As Integer) As Boolean
      End Function

      <DllImport("coredll.dll")> _
      Public Shared Function CryptReleaseContext( _
         ByVal hProv As IntPtr, ByVal dwFlags As Integer) As Boolean
      End Function

      <DllImport("coredll.dll")> _
      Public Shared Function CryptGenRandom( _
         ByVal hProv As IntPtr, ByVal dwLen As Integer, _
         ByVal pbBuffer() As Byte) As Boolean
      End Function
   End Class

   ' all static methods
   Private Sub New()
   End Sub

   ' Return a new System.Guid object.
   Public Shared Function NewGuid() As Guid
      Dim hCryptProv As IntPtr = IntPtr.Zero
      Dim guid As Guid = guid.Empty

      Try
         ' holds  random bits  for  guid
         Dim bits(ConstValues.ByteArraySize - 1) As Byte

         ' get crypto provider handle
         If Not WinApi.CryptAcquireContext(hCryptProv, Nothing, Nothing, _
            WinApi.PROV_RSA_FULL, WinApi.CRYPT_VERIFYCONTEXT) Then
            Throw New SystemException( _
               "Failed  to acquire cryptography  handle.")
         End If

         ' generate a 128 bit (16 byte) cryptographically random  number
         If Not WinApi.CryptGenRandom(hCryptProv, bits.Length, bits) Then
            Throw New SystemException( _
               "Failed  to generate  cryptography random  bytes.")
         End If

         ' set the variant
         bits(ConstValues.VariantByte) = bits(ConstValues.VariantByte) And _
            CByte(ConstValues.VariantByteMask)
         bits(ConstValues.VariantByte) = bits(ConstValues.VariantByte) Or _
            CByte(GuidVariant.Standard << ConstValues.VariantByteShift)

         ' set the version
         bits(ConstValues.VersionByte) = bits(ConstValues.VersionByte) And _
            CByte(ConstValues.VersionByteMask)
         bits(ConstValues.VersionByte) = bits(ConstValues.VersionByte) Or _
            CByte(GuidVersion.Random << ConstValues.VersionByteShift)

         ' create the new System.Guid object
         guid = New Guid(bits)
      Finally
         ' release the crypto provider handle
         If Not hCryptProv.Equals(IntPtr.Zero) Then
            WinApi.CryptReleaseContext(hCryptProv, 0)
         End If
      End Try

      Return guid
   End Function
End Class

GUID Trivia

Here are some GUID trivia questions you can use to impress your co-workers. You can run the PocketGuid test application or guidgen.exe on your desktop to check the questions; however, checking the last question might take a while.

  • Question: What is the only nibble (4 bits) that is always the same?
    • Answer: The 13th nibble specifies the GUID version and is always set to 4 for Windows 2000 and later. Example, 8743428c-ef91-4d05-9e7c-4a2e856e813a.
  • Question: What nibble only contains the values 8, 9, A, or B?
    • Answer: The 17th nibble contains the variant information so it will always be 8, 9, A or B since the upper bit is always set and next bit is always cleared. Example, 8743428c-ef91-4d05-9e7c-4a2e856e813a.
  • Question: How many GUID combinations are there?
    • Answer: There are 122 random bits (128 – 2 for variant - 4 for version) so this calculates to 2^122 or 5,316,911,983,139,663,491,615,228,241,121,400,000 possible combinations.

Links

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --