Create a New Universally Unique IDentifier (UUID)
by
, 3-Apr-2011 at 09:31 PM (364929 Views)
If you are in a need to have a unique ID in your application you might want to make use of a Universally Unique IDentifier (UUID). The term UUID is interchangeable with GUID (Globally Unique ID). A UUID is a string that contains five blocks of hexadecimal digits. The Windows API has functions for this and in this blog I show you how to create UUIDs in Visual DataFlex.
An example of a valid UUID string is: 2CA263F1-5C94-11E0-84CC-002170FBAC5B. As you can see it consists of 8 hexadecimal digits followed by a dash, followed by three groups of 4 hexadecimal digits separated by a dash, followed by 12 hexadecimal digits prefixed with a dash.
Data Structure
For the API functions we use below we need a structure with four members. Define the following structure definition in your application:
Random or SequentialCode:Struct tUUID UInteger uiData1 UShort usData2 UShort usData3 UChar[8] ucData4 End_Struct
The Windows API has two different functions to generate a UUID. One generates a sequential UUID and the other one a random one. UUIDs are always unique but it might sound a bit weird when someone sees UUIDs that have a sequential, incremental value.
A sample of 3 randomly generated UUID is:
And an example of 3 sequential UUIDs is:Code:1: ADFF9239-85B6-42EC-9FDD-41DC4C8AF6FA 2: F9B0CC28-A63A-4672-BF42-3B0E7508299E 3: 1E345F18-FC3B-492D-B22D-E18ABBDC7BE9
As you can see the UUIDs are almost the same. If you use such a UUID as a record identifier it would not matter at all since you are already used to use sequential numbers for customer, order and not to forget record numbers.Code:1: 57F2B390-5D82-11E0-84CC-002170FBAC5B 2: 57F2B391-5D82-11E0-84CC-002170FBAC5B 3: 57F2B392-5D82-11E0-84CC-002170FBAC5B
So how to get these UUID's? The Windows API function definitions are:
For the use of these functions make use of the following DataFlex code functions:Code:External_Function WinAPI_UuidCreate "UuidCreate" Rpcrt4.dll Address Uuid Returns Integer External_Function WinAPI_UuidCreateSequential "UuidCreateSequential" Rpcrt4.dll Address aUuid Returns Integer
If you look at the above code you will see that the UUID variables do not use the earlier in this blog mentioned structure definition. The variables are made from a structure named tUUIDEx. This is an extended version of tUUID that I created to store a function status value. The definition of tUUIDEx is:Code: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
Now we have a UUID how do we get that nice hexadecimal string out of the values? You can do this with the Windows API function UuidToString and to use this in your Visual DataFlex application add the following code to your application:Code:Struct tUUIDEx tUUID UUID Integer iStatus End_Struct
The first function is the conversion function and the second frees up the memory allocated by the funciton call. The 3rd function is to do the reverse of the first one. It will convert a UUID string into a tUUID struct value collection. Use the 3 functions via the following methods:Code: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
NillCode: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
The Windows API also has a function to create a NILL (not NULL) UUID. You could see this as recnum that is zero when no record has been saved. A NILL UUID is always looking as: 00000000-0000-0000-0000-000000000000.
The API definition is:
You use the above function as follows:Code:External_Function WinAPI_UuidCreateNil "UuidCreateNil" rpcrt4.dll Address aUuid Returns Integer
CompareCode:Function NilUUID Returns tUUID tUUID UUID Integer iRetval Move (WinAPI_UuidCreateNil (AddressOf (UUID))) to iRetval Function_Return UUID End_Function
The Windows API set also has a set of functions to compare the UUIDs with eachother. There is a function to test if two UUIDs are identical, if they are greater or bigger than eachother of if a UUID is a NILL UUID. The Windows API function codes are:
And you use the with:Code: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
The Compare function returns -1 if UUID1 is less than UUID2, 0 if they are identical and 1 if UUID1 is greater than UUID2.Code: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
Constants
To complete the code to generate and compare UUIDs you need to add the following constant definitions to your code.
With all the above you will be able to create and compare UUIDs. Have fun!Code: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