Archive

Archive for 30 septiembre 2011

Trabajar con identificadores únicos


El uso de tecnologías COM popularizó el concepto de identificadores únicos, o GUIDs (Globally Unique Identifier). Los GUIDs son valores de 128 bits usualmente agrupados en cuatro bloques:

1.- Un bloque de 32 bits.

2.- Un bloque de 16 bits.

3.- Un bloque de 16 bits.

4.- Un bloque de 64 bits (agrupado en ocho segmentos de un byte).

Usualmente se representan en texto de la siguiente forma:

{21EC2020-3AEA-1069-A2DD-08002B30309D}

donde los primeros ocho caracteres comprendidos entre las llaves son el primer bloque, luego vienen cuatro y cuatro caracteres para el segundo y tercer bloque, y finalmente un bloque de cuatro caracteres seguido por uno más de doce, que en conjunto representan el último bloque de 64 bits.

Dado que los GUIDs son valores de 128 bits, el número de combinaciones existentes es de 2128, lo cual raya en los 3.4 x 1038 (3.4 seguido de 37 ceros). La posibilida de que aleatoriamente se generen valores iguales es ínfima, además de que el algoritmo para generarlos pone candados para evitar que esto ocurra.

Los GUIDs se usan en muchos lados. COM los usa para identificar sus componentes, Windows los usa para identificar los nombres de archivos, carpetas, usuarios y otros símbolos de sistema, e incluso son usados en bases de datos para identificar registros únicos.

Tan usados son que el .NET Framework viene con su propia clase, System.Guid, para trabajar con éstos. Pero ¿qué pasa con C y C++? No hay clase alguna como en.NET… pero sí existe una estructura, GUID, la cual se define así:

typedef struct _GUID {
    unsigned long  Data1;
    unsigned short Data2;
    unsigned short Data3;
    unsigned char  Data4[ 8 ];
} GUID;

Ahora, la estructura vacía no ayuda mucho. Sin embargo existen funciones del API de Windows para trabajar con ésta. Resumo algunas a continuación.

1.- UuidCreateNil. Crea un GUID vacío (i.e. {00000000-0000-0000-0000-000000000000}).

2.- UuidFromString. Crea una estructura GUID a partir de una cadena de texto. Por ejemplo:

const wchar_t* sz = L"{21EC2020-3AEA-1069-A2DD-08002B30309D}";
GUID guid;
::UuidFromString((unsigned short*)sz, &guid);

3.- UuidCreate. Crea una estructura GUID de acuerdo al algoritmo para la creación de identificadores únicos. Easy peasy:

GUID guid;
::UuidCreate(&guid);

Nota que el GUID usa el primer algoritmo para la creación de GUIDs, el cual se basa en la dirección MAC de la tarjeta de red. Dado que esto crea un hueco de seguridad (cualquier GUID puede rastrear la MAC del equipo donde se creó), se recomienda crear UuidCreateSequential, función que usa un algoritmo más reciente.

4.- UuidToString. Hace lo contrario a UuidFromString: nos devuelve la representación de texto a partir de un GUID.

GUID guid;
::UuidCreate(&guid);

wchar_t* pstr;
::UuidToString(&guid, (unsigned short**)&pstr);
// hacer algo con pstr
::RpcStringFree(pstr);

5.- UuidEqual. Nos permite determinar si dos GUIDs son iguales.

RPC_STATUS status;
GUID guid1 = ...;
GUID guid2 = ...;
BOOL equals = ::UuidEqual(&guid1, &guid2, &status);

6.- UuidCompare. Similar a UuidEqual, solo que nos dice si un GUID es mayor o menor a otro.

RPC_STATUS status;
GUID guid1 = ...;
GUID guid2 = ...;
int compare = ::UuidCompare(&guid1, &guid2, &status);

7.- UuidIsNil. Regresa TRUE si el GUID es vacío. Es similar a usar UuidEquals con un GUID, y con un valor devuelto por UuidCreateNil.

8.- UuidCreateSequential. Similar a UuidCreate, sólo que usa el último algoritmo para creación de GUIDs, el cual no se basa en la dirección MAC de la tarjeta de red. Checa el valor devuelto por la función, ya que puede devolverte tres valores:

  • RPC_S_OK si todo salió bien.
  • RPC_S_UUID_LOCAL_ONLY si el GUID es único sólo en la máquina actual.
  • RPC_S_UUID_NO_ADDRESS si el hardware del equipo no permite la creación de un valor único.

Puedes buscar más información en MSDN

Categorías:Apunte, C++, WIN-32 Etiquetas: ,