Criando um novo Identificador Único Universal (UUID)
03 de Abril de 2011
Por Vincent Oorsprong
Se você precisa ter um ID único em sua aplicação, então você pode querer usar um Identificador Único Universal ou Universally Unique IDentifier (UUID). O termo UUID é utilizando também como GUID (Globally Unique ID ou Identificador Único Global). Um UUID é uma string que contém cinco blocos de dígitos hexadecimais. A API do Windows possui funções para isto e neste blog mostrarei a você como criar UUIDs no DataFlex.
Um exemplo de string UUID válida é: 2CA263F1-5C94-11E0-84CC-002170FBAC5B. Como podemos observar, ela consiste de 8 dígitos hexadecimais seguidos de um traço, seguidos por um grupo de 4 dígitos hexadecimais separados por um traço e mais 12 dígitos hexadecimais precedidos de um traço.
Estrutura de Dados
Para as funções da API que utilizaremos a seguir, precisaremos de uma estrutura com quatro membros. Defina a seguinte estrutura na sua aplicação:
Struct tUUID
UInteger uiData1
UShort usData2
UShort usData3
UChar[8] ucData4
End_Struct
Randômico ou Sequencial
A API do Windows possui duas funções diferentes para gerar UUID. Uma delas gera um UUID sequencial e a outra gera um UUID randômico. Os UUIDs são sempre únicos, porém isto pode parecer estranho ver UUIDs que têm uma sequência, um valor incrementado. Três exemplos de UUIDs gerados randomicamente são:
1: ADFF9239-85B6-42EC-9FDD-41DC4C8AF6FA
2: F9B0CC28-A63A-4672-BF42-3B0E7508299E
3: 1E345F18-FC3B-492D-B22D-E18ABBDC7BE9
Três exemplos de UUIDs sequenciais:
1: 57F2B390-5D82-11E0-84CC-002170FBAC5B
2: 57F2B391-5D82-11E0-84CC-002170FBAC5B
3: 57F2B392-5D82-11E0-84CC-002170FBAC5B
Então como gerar esses UUIDs? As definições das funções da API do Windows são:
External_Function WinAPI_UuidCreate "UuidCreate" Rpcrt4.dll Address Uuid Returns Integer
External_Function WinAPI_UuidCreateSequential "UuidCreateSequential" Rpcrt4.dll Address aUuid Returns Integer
Para utilizarmos essas funções, precisaremos das seguintes funções criadas no DataFlex:
Function CreateUUID Returns tUUIDEx
tUUIDEx UUID
Integer iRetval
Move (WinAPI_UuidCreate (AddressOf (UUID.UUID))) to UUID.iStatus
Function_Return UUID
End_Function
Function CreateSeqUUID Returns tUUIDEx
tUUIDEx UUID
Integer iRetval
Move (WinAPI_UuidCreateSequential (AddressOf (UUID.UUID))) to UUID.iStatus
Function_Return UUID
End_Function
Se você observar o código acima, perceberá que as variáveis UUID não utilizam a estrutura criada no início deste blog. As variáveis são baseadas numa estrutura chamada tUUIDEx. Esta é uma versão estendida de tUUID que eu criei para armazenar um valor de status da função. A definição da estrutura tUUIDEx é a seguinte:
Struct tUUIDEx
tUUID UUID
Integer iStatus
End_Struct
Agora que temos um UUID, como fazemos para extrair uma string hexadecimal desses valores? Você pode fazê-lo com a função UuidToString da API do Windows. Para adicionar essa função na sua aplicação DataFlex, adicione o seguinte código à sua aplicação:
External_Function WinAPI_UuidToString "UuidToStringA" Rpcrt4.dll Address aUuid Address lpUUIDString Returns Integer
External_Function WinAPI_RpcStringFree "RpcStringFreeA" Rpcrt4.dll Address pStr Returns Integer
External_Function WinAPI_UuidFromString "UuidFromStringA" Rpcrt4.dll Address lpUUIDString Address aUuid Returns Integer
A primeira função é a função de conversão e a segunda libera a memória alocada pela chamada à função. A terceira função faz o inverso da primeira. Ela converterá uma string UUID em uma coleção da estrutura tUUID. Utilize a terceira função por meio dos seguintes métodos:
Function UUIDToString tUUID UUID Returns String
Address UUIDPointer
String sUUID
Integer iRetval
Move 0 to UUIDPointer
Move (WinAPI_UuidToString (AddressOf (UUID), AddressOf (UUIDPointer))) to iRetVal
If (iRetval = RPC_S_OK) Begin
Move UUIDPointer to sUUID
Move (WinAPI_RpcStringFree (AddressOf (UUIDPointer))) to iRetval
Move (Uppercase (sUUID)) to sUUID
End
Else Begin
Get Error_Text of Desktop 10 to sUUID
End
Function_Return sUUID
End_Function
Function UUIDFromString String sUUID Returns tUUIDEx
tUUIDEx UUID
Integer iRetval
Move (WinAPI_UuidFromString (AddressOf (sUUID), AddressOf (UUID.UUID))) to UUID.iStatus
Function_Return UUID
End_Function
Nill
A API do Windows também contém uma função para criar um UUID NILL (não NULL). Você pode entender ver isso como um recnum que é zero quando nenhum registro foi salvo. Um UUID NILL é sempre: 00000000-0000-0000-0000-000000000000.
A definição da API é:
External_Function WinAPI_UuidCreateNil "UuidCreateNil" rpcrt4.dll Address aUuid Returns Integer
Você pode utilizar a função acima da seguinte forma:
Function NilUUID Returns tUUID
tUUID UUID
Integer iRetval
Move (WinAPI_UuidCreateNil (AddressOf (UUID))) to iRetval
Function_Return UUID
End_Function
Comparação
A API do Windows tem um conjunto de funções para comparar UUIDs entre si. Existe uma função para testar se dois UUIDs são iguais, se um é maior ou mais longo que o outro ou se um UUID é um NILL UUID.
External_Function WinAPI_UuidEqual "UuidEqual" rpcrt4.dll Address aUuid1 Address aUuid2 Address aUUIDStatus Returns Integer
External_Function WinAPI_UuidCompare "UuidCompare" rpcrt4.dll Address aUuid1 Address aUuid2 Address aUUIDStatus Returns Integer
External_Function WinAPI_UuidIsNil "UuidIsNil" rpcrt4.dll Address aUuid Address aUUIDStatus Returns UShort
E você as utilizam com:
Function UUIDEqual tUUID UUID1 tUUID UUID2 Returns Boolean
Integer iStatus iRetval
Move 0 to iStatus
Move (WinAPI_UuidEqual (AddressOf (UUID1), AddressOf (UUID2), AddressOf (iStatus))) to iRetval
Function_Return iRetval
End_Function
Function UuidCompare tUUID UUID1 tUUID UUID2 Returns Integer
Integer iStatus iRetval
Move 0 to iRetval
Move (WinAPI_UuidCompare (AddressOf (UUID1), AddressOf (UUID2), AddressOf (iStatus))) to iRetval
Function_Return iRetval
End_Function
Function UUIDIsNil tUUID UUID Returns Boolean
Integer iStatus iRetval
Move 0 to iStatus
Move (WinAPI_UuidIsNil (AddressOf (UUID), AddressOf (iStatus))) to iRetval
Function_Return iRetval
End_Function
The Compare function returns -1 if UUID1 is less than UUID2, 0 if they are identical and 1 if UUID1 is greater than UUID2.
Constantes
Para completar o código para gerar e comparar UUIDs, você precisa adicionar as seguintes definições de constantes ao seu código:
Define ERROR_SUCCESS for 0 // The operation completed successfully.
Define ERROR_INVALID_HANDLE for 6 // The handle is invalid.
Define ERROR_OUTOFMEMORY for 14 // Not enough storage is available to complete this operation.
Define ERROR_INVALID_PARAMETER for 87 // The parameter is incorrect.
Define ERROR_INSUFFICIENT_BUFFER for 122 // The data area passed to a system call is too small.
Define ERROR_MAX_THRDS_REACHED for 164 // No more threads can be created in the system.
Define ERROR_IO_PENDING for 997 // Overlapped I/O operation is in progress.
Define ERROR_NONE_MAPPED for 1332 // No mapping between account names and security IDs was done.
Define ERROR_INVALID_SECURITY_DESCR for 1338 // The security descriptor structure is invalid.
Define ERROR_TIMEOUT for 1460 // This operation returned because the timeout period expired.
Define RPC_S_INVALID_STRING_UUID for 1705 // The string universal unique identifier (UUID) is invalid.
Define RPC_S_INVALID_TAG for 1733 // The tag is invalid.
Define RPC_S_UUID_NO_ADDRESS for 1739 // No network address is available to use to construct a universal unique identifier (UUID).
Define RPC_S_INVALID_BOUND for 1734 // The array bounds are invalid.
Define RPC_X_ENUM_VALUE_OUT_OF_RANGE for 1781 // The enumeration value is out of range.
Define ERROR_INVALID_USER_BUFFER for 1784 // The supplied user buffer is not valid for the requested operation.
Define ERROR_NOT_ENOUGH_QUOTA for 1816 // Not enough quota is available to process this command.
Define RPC_S_UUID_LOCAL_ONLY for 1824 // A UUID that is valid only on this computer has been allocated.
Define RPC_X_WRONG_PIPE_ORDER for 1831 // An invalid operation was attempted on an RPC pipe object.
Define RPC_X_WRONG_PIPE_VERSION for 1832 // Unsupported RPC pipe version.
Define RPC_S_OK for ERROR_SUCCESS
Define RPC_S_INVALID_ARG for ERROR_INVALID_PARAMETER
Define RPC_S_OUT_OF_MEMORY for ERROR_OUTOFMEMORY
Define RPC_S_OUT_OF_THREADS for ERROR_MAX_THRDS_REACHED
Define RPC_S_INVALID_LEVEL for ERROR_INVALID_PARAMETER
Define RPC_S_BUFFER_TOO_SMALL for ERROR_INSUFFICIENT_BUFFER
Define RPC_S_INVALID_SECURITY_DESC for ERROR_INVALID_SECURITY_DESCR
Define RPC_S_ACCESS_DENIED for ERROR_ACCESS_DENIED
Define RPC_S_SERVER_OUT_OF_MEMORY for ERROR_NOT_ENOUGH_SERVER_MEMORY
Define RPC_S_ASYNC_CALL_PENDING for ERROR_IO_PENDING
Define RPC_S_UNKNOWN_PRINCIPAL for ERROR_NONE_MAPPED
Define RPC_S_TIMEOUT for ERROR_TIMEOUT
Define RPC_S_NOT_ENOUGH_QUOTA for ERROR_NOT_ENOUGH_QUOTA
Define RPC_X_NO_MEMORY for RPC_S_OUT_OF_MEMORY
Define RPC_X_INVALID_BOUND for RPC_S_INVALID_BOUND
Define RPC_X_INVALID_TAG for RPC_S_INVALID_TAG
Define RPC_X_ENUM_VALUE_TOO_LARGE for RPC_X_ENUM_VALUE_OUT_OF_RANGE
Define RPC_X_SS_CONTEXT_MISMATCH for ERROR_INVALID_HANDLE
Define RPC_X_INVALID_BUFFER for ERROR_INVALID_USER_BUFFER
Define RPC_X_PIPE_APP_MEMORY for ERROR_OUTOFMEMORY
Define RPC_X_INVALID_PIPE_OPERATION for RPC_X_WRONG_PIPE_ORDER
Com tudo isso você poderá criar e comparar UUIDs. Divirta-se!