What's the difference between UuidFromString, IIDFromString, CLSIDFromString, GUIDFromString...


A GUID and a CLSID and an IID are all the same as a UUID, but there are separate functions for converting a string into a GUID, CLSID, IID, and UUID. Are they all equivalent? If not, what's the difference? And which one should I use?

The basic form for a UUID string is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx where each x is a hexadecimal digit, case-insensitive. (I personally prefer all-uppercase.) All of the parsing functions under discussion use this basic form as their basis of exploration. Some functions expect the basic form to be enclosed in curly braces; others do not.

Let's start with Uuid­From­String. It takes a string in basic form without curly braces. As a special case, if you pass NULL instead of a valid string pointer, the function still succeeds and sets the result to GUID_NULL.

Next up is IID­From­String. This function takes a string in basic form with curly braces. It also has the behavior that passing NULL as the string results in success and GUID_NULL.

Slightly more complicated is CLSID­From­String. In addition to accepting a brace-enclosed string (which is treated as a GUID), it also accepts a ProgId. In the ProgId case, it returns the CLSID associated with that ProgId. For example, if you ask for Paint.Picture, it will return the GUID {D3E34B21-9D75-101A-8C3D-00AA001A1652}. As with the other functions, passing NULL is valid and results in GUID_NULL.

Last is GUID­From­String. This function is one of those "Not guaranteed to be supported beyond Windows Vista" functions, so you should probably steer clear. (Another clue that calling it is probably a bad idea: The function is not exposed in any header file or import library.) But if you insist: It accepts a brace-enclosed string, and NULL is not allowed. Furthermore, it ignores any garbage after the trailing brace. This function was not intended for public consumption, so these strange quirks are not entirely unexpected.

Let's summarize in a table, since that seems to be popular. I added a final column describing whether the function available in A/W variants or is Unicode-only.

Function Expected format NULL allowed? Character set support
Uuid­From­String xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Yes ANSI and Unicode
IID­From­String {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} Yes Unicode only
CLSID­From­String {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
ProgId
Yes Unicode only
GUID­From­String {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}* No ANSI and Unicode
Comments (24)
  1. Brian Friesen says:

    Thanks, interesting to learn the differences.  Another key point that might play a role in which API to call is the library where they are located.  Both IIDFromString and CLSIDFromString are in ole32.dll which most apps link to already.  UuidFromString is located in rpcrt4.dll which might require the developer to pull in an additional library.  And GUIDFromString is in shell32.dll.

  2. Eddie says:

    What is the story behind the curly braces?  Were they added to delineate the GUID in a larger string?

  3. Ian Boyd says:

    I had a strange bug come up about two years ago. We were parsing user input, checking if they were typing a GUID.

    CLSIDFromString was converting the string "m" into the guid "{4ED063C9-4A0B-4B44-A9DC-23AFF424A0D3}". This was completely nonsensical until i used Bing to google the returned GUID, and discovered that it was some malware. "M" was the ProgID, and "{4ED063C9-4A0B-4B44-A9DC-23AFF424A0D3}" was its corresponding CLSID.

    Which is how i learned that CLSIDFromString hits the registry every time it's called. Using it to try to parse strings into a GUID is a bad idea. We switched to IIDFromString.

    Perhaps i'll change it again to use UUIDFromString; as i'm no more interested in an Interface Identifer as i was interested in a Class Identifier.

  4. mikeb says:

    @Ian Boyd:

    >>  used Bing to google...

    Classic.

  5. Henri Hein says:

    This was useful.  The curly braces always trips me up.  It's like one of those Unix things, where you just have to know whether to include them or not.

  6. Rich Shealer says:

    @mikeb

    Wow Google is embedded deep. When I read that I didn't even trip on the "Bing to google" phrase until you pointed it out.

  7. skSdnW says:

    @Raymond: You forgot SHCLSIDFromString (I can't find the shell extension docs for Win95 but it is probably part of the mini-COM for extensions that don't link to ole32)

    @Ian Boyd: The implementation on Win8 tries to parse as a guid first and might not hit the registry. It is the sane thing to do and probably does this in all versions. If only it was documented...

  8. Electron Shepherd says:

    @skSdnW: "The implementation on Win8 ... If only it was documented"

    You document the interface, never the implementation.

  9. foo says:

    I like uppercase guids too (uuidgen -c ...). And mostly just used CLSIDFromProgID to get the guid from a ProgID. But that's because we knew we were dealing with prog ids as input. Also, I haven't bing'ed the googles, but would there be a standard function to convert the string C struct representation of a guid (uuidgen -s) into a binary guid? Probably not, since that was mostly just for pasting into program source code?

  10. Nico says:

    In the past I was somewhat ambivalent about the case of letters in UUIDs, but as I've started to see them more (our current database uses them a lot), I've started to prefer lower-case letters.  Seeing big lists of uppercase UUIDs feels like I'm being shouted at by my computer :(

  11. skSdnW says:

    @Electron Shepherd: Obviously but the way it is now you would expect the API to fail on anything that is not a valid GUID string, it's even implied by its name. Even worse, the result can change from machine to machine or even in the lifetime of a process if something is registered/unregistered while it is running! This implementation is not an accident and forcing people to discover it the hard way is cruel.

  12. mh25000 says:

    A column of type 'uniqueidentifier' (which is what newid() returns) in a table in SQL Server returns a string in the form "12345678-1234-1234-1234-123456789ABC" when you select it.  If you cast the value to BINARY it comes back as 0x78563412341234121234123456789ABC", in other words the bytes in the first three sections, but not the last two, are reordered.

    Is there an interesting reason for this?  Something I should know about?

    It isn't a problem, but I need to code around it because in the database API I'm using (DB-Library, yes an API from the last century) the column comes back as BINARY instead of CHAR(36).

  13. mh25000 says:

    You can see for yourself with the query

       select cast(0x12345678123456789abc123456789abc as uniqueidentifier)

    in any SQL Server database.

    Nevermind, I've just worked it out by having a look at the UUID type (that UuidFromString modifies).  It's a struct of { LONG, SHORT, SHORT, CHAR[8] }, and the three ints change due to byte ordering while the char array stays the same.  But now the question is why the struct is the way it is, instead of { LONG, SHORT, SHORT, SHORT, CHAR[6] }?

  14. foo says:

    @mh25000 - I'm guessing Little Endian machine order for the DWORD and 2 WORDS

  15. Sander says:

    There are two commonly used GUID serialization forms when you trip between string and binary formats.

    The form with the bytes in funny order is often called the Microsoft form and is used, as you might guess, primarily on Microsoft software. The other form with no touching of the bytes and straight up "removing the dashes" style serialization is what I call the Linux style and it is often used with open source software everywhere and is almost universally used on Linux.

    GUID: 01020304-0506-0708-090a-0b0c0d0e0f10

    Microsoft format: 0403020106050807090A0B0C0D0E0F10

    Linux format: 0102030405060708090A0B0C0D0E0F10

    While in concept it may looks like an endianness question, in reality there is no relation to machine endianness and both forms are used on all sorts of machines regardless of endianness. You always need to explicitly know not only that you have a serialized GUID in those 16 bytes but also what the serialization format is.

    Because of the similarity to endianness (and potential actual roots in it 25 years ago, though no longer relevant) the Microsoft format is called little endian and the Linux format is called big endian.

  16. Medinoc says:

    Are there any such considerations for the various StringFromXxxx() functions?

  17. Cesar says:

    @Sander: what you called the "Linux format" is actually RFC 4122, the UUID RFC. Quoting from it:

    "The fields are encoded as 16 octets, with the sizes and order of the fields defined above, and with each field encoded with the Most Significant Byte first (known as network byte order)."

    What you called the "Microsoft format" is the in-memory representation of the struct they use to represent an UUID, recalling that Windows runs on little-endian CPUs. The first three fields are integers larger than a byte, the other fields are either byte-sized or an array of bytes.

  18. foo says:

    > But now the question is why the struct is the way it is

    Yeah sorry. Wrote my reply before reading your second post. And that is a good question. Maybe that structure layout made calculating the first version of the guid generation algorithm fast?

  19. DWalker says:

    @rude name: "The implementation on Win8 tries to parse as a guid first and might not hit the registry"  But how would the implementation know that the given GUID was, or was not, a known CLSID unless it checked the registry every time?

  20. SI says:

    CLSIDFromString converts any passed GUID string to a binary GUID, the GUID does not need to actually be registered as a CLSID.

  21. DMarschall says:

    I have two annotations:

    1. I am very disappointed about the poor documentation at MSDN in regards to CLSIDFromString: msdn.microsoft.com/.../ms680589(v=vs.85).aspx . The in- and outputs aren't explained at all. So all we have is your blog, but no official documentation about valid input strings. It isn't even officially clear if a GUID can be used as input, because a CLSID is technically not a GUID ( stackoverflow.com/.../how-do-i-convert-a-lpwstr-to-a-guid ). In the comments, people did already complain about that in 2012, but I assume Microsoft doesn't care about these complaints.

    2. About GUIDFromString(): Why did someone implement this function for internal purpose? I assume it is one of the cases where a developer re-invented the wheel, because they didn't knew it was already implemented somewhere else -- that happened to me a few times, too.

    [You're assuming that somebody actually reads the comments and actively chose to ignore them. I suspect nobody reads the comments. -Raymond]
  22. More diversity says:

    A wonder that there's no function which is a hybrid of the first two, making the braces optional...

    [That is a great first step toward creating a security hole. (Inconsistent enforcement.) -Raymond]
  23. Andrew says:

    Or perhaps a version making just the left brace optional, a version making the right brace optional, and a version making both braces optional.

  24. Scarlet Manuka says:

    @More diversity:

    >a hybrid of the first two, making the braces optional

    ... but not allowing NULL input, a design flaw which later has to be rectified by making an Ex version because testing reveals a large number of programs are relying on the call failing on NULL input to do their error checking...

Comments are closed.

Skip to main content