An API-based CreateGUID function requires at the very least a single API function
call. The CoCreateGuid function seems to be the most popular API used for this
task. However, as the remarks in its documentation points out, it in fact calls
another API to do the real job. The RPC function UuidCreate generates the actual
Universally Unique Identifiers (UUID), which Microsoft has implemented as the GUID.
Manually converting the GUID/UUID structure to a String can be quite cumbersome
to do in VB. Fortunately, two APIs already exists for this purpose: the
UuidToString function and the StringFromGUID2 function. One drawback when using
UuidToString is that the function RpcStringFree needs to be called to release the
memory allocated by the RPC run-time library. StringFromGUID2, on the other hand,
just needs to be provided a buffer to which it will write the results.
StringFromGUID2 does have a limitation though, in that it only works with Unicode
strings. But that is easily resolved by declaring the lpsz parameter As Long and
by using StrPtr.
When allocating buffers, the intrinsic VB functions Space$ and String$ are often
used. It has already been proven that Space$ is the faster of the two. But if
utmost speed is a major factor, then SysAllocStringLen/SysReAllocStringLen are
the functions to call. While writing a Declare statement for SysAllocStringLen
that returns a "proper" VB String looks impossible (it is best called from a
Type Library), SysReAllocStringLen's syntax, on the other hand, is much easier
to convert.
Here are the necessary API declarations:
Private Type UUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(7) As Byte
End Type
Private Declare Function UuidCreate Lib "rpcrt4.dll" ( _
ByRef lpUuid As Any _
) As Long
Private Declare Function StringFromGUID2 Lib "ole32.dll" ( _
ByRef rguid As Any, _
ByVal lpsz As Long, _
ByVal cchMax As Long _
) As Long
Private Declare Function SysReAllocStringLen Lib "oleaut32.dll" ( _
ByVal pBSTR As Long, _
Optional ByVal pszStrPtr As Long, _
Optional ByVal Length As Long _
) As Long
UuidCreate's lpUuid parameter is typed As Any to allow either GUID or UUID
structures (which are identical) or even Long Arrays. The same thing is done to
StringFromGUID2's rguid argument.
SysReAllocStringLen's first parameter should be passed a pointer to a BSTR.
Because VB Strings are also known as BSTRs, a String variable's address is
therefore retrieved with VarPtr. The second parameter, on the other hand, should
be passed a pointer to some other string's contents, i.e., with StrPtr. If this
parameter is skipped, SysReAllocStringLen will not initialize the data; thus the
resulting string will contain garbage. The final optional parameter specifies how
large the new string will be. If not given, a zero-length string ("") will be
returned.
And now, for the CreateGUID function:
Public Function CreateGUID() As String
Const RPC_S_OK = 0&: Dim udtUUID As UUID
If UuidCreate(udtUUID) = RPC_S_OK Then _
SysReAllocStringLen VarPtr(CreateGUID), , 38&: _
StringFromGUID2 udtUUID, StrPtr(CreateGUID), 39&
End Function
If UuidCreate returns successfully, then the implicit function variable is used
as a buffer and allocated with the exact size required (SysReAllocStringLen
appends a Null character before returning the string). By not specifying a string
to copy from, SysReAllocStringLen leaves the output string uninitialized. This
method makes it faster than using the Space$ function. Finally, StringFromGUID2
writes the converted value into the supplied buffer, which now becomes
CreateGUID's return value.
The included benchmark module compares the performance of this function against
several other GUID functions from this site, as well as from two other.