Why are there four functions for parsing strings into GUIDs, and why are they in three different DLLs?

Some time ago, we discussed the differences among various functions that take a string and produce a GUID-like thing. Let's look at that table.

Function Exported by
Uuid­From­String rpcrt4.dll
IID­From­String ole32.dll
CLSID­From­String ole32.dll
GUID­From­String shell32.dll

Why are there four such functions, and more importantly, why are they in three different DLLs?

As you might expect, the answer comes from history.

The first two functions on the scene are the ones in the middle of the table. IID­From­String and CLSID­From­String come from the original 32-bit OLE library. They differ in their intended use. The second one is for parsing strings that represent OLE objects. It so happens that you are allowed to do this either by specifying the raw GUID as a string, or by specifying the programmatic ID for the class. That's why CLSID­From­String does the extra work of looking in HKEY_CLASSES_ROOT to convert the string to a CLSID.

On the other hand, interface IDs have no such alternate notation, so the IID­From­String function accepts only stringized GUIDs.

At this point in time, OLE was a monolithic DLL. It then became apparent that the monolithic OLE DLL was really doing several things: It managed document linking and embedding (OLE). As part of that work, it also had to manage the component object model (COM). And in the case where the components are in different processes, it needs to perform remote procedure calls (RPC).

The remote procedure call functionality was useful in its own right, so the OLE team spun it off into its own library, and OLE would be one of many clients of the new library. That new library was called RPCRT4, which I'm guessing stands for "remote procedure call runtime, fourth attempt" (?).

The remote procedure call library therefore had to have its own parser for stringized GUIDs; it couldn't call up into OLE because that would be a layering violation. (RPC is the low-level component and OLE is the high-level component.) And besides, the components which were using the raw RPC layer were doing so because they explicitly didn't want OLE. Having the string parsing function in OLE would force components to load OLE, which ruined the point of splitting RPC into its own library. For want a string-parsing function the kingdom was lost.

The last function on the scene is GUID­From­String. This was written by the shell team back in the days of OLE Chicken. (not to be confused with Chicken Ole). The shell needed only a limited subset of OLE in order to function. To avoid the performance impact of loading all of OLE (and allocating a whopping 32KB of memory), it contained a miniature copy of OLE; just enough to let the shell do what it needed. And one of the things in that miniature copy of OLE was a function to parse strings into GUIDs.

Comments (14)
  1. Darran Rowe says:

    I always find these posts interesting because they highlight again how restricted memory was, and the things that we used to do to save that whopping 32KB.
    For rpcrt4, I always thought of it as version 4, but I guess in this situation there is no difference because I don’t remember ever seeing rpcrt(1), rpcrt2 or rpcrt3.

    1. Klimax says:

      I think those previous versions were internal to OEL development and as such not visible to outside. And to help keep track of things, they put version into filename of new library.

  2. skSdnW says:

    There are actually 3 more; CLSIDFromStringWrap, SHCLSIDFromString, and RtlGUIDFromString.

    1. henke37 says:

      Now we have to wait until 2020 for part two that covers the additional functions.

  3. Jim Dagg says:

    “Remote Procedure Call Runtime, Take 4”, maybe?

  4. Off-topic: Is there some configuration problem with the blog software or database backend? For some articles, when I refresh them, I sometimes get different sets of comments, or sometimes a 404 page, as if some of the backend web hosts behind the load balancer are connecting to a different database, so that the view I get depends on which backend host I hit.

    For example, if I repeatedly refresh https://blogs.msdn.microsoft.com/oldnewthing/20160324-00/?p=93194 , I get either a 404 or a post with 15 comments; and if I repeatedly refresh https://blogs.msdn.microsoft.com/oldnewthing/20160323-00/?p=93193 , I get a post which *says* it has 29 comments, but half the time, only 24 comments are shown.

    1. I’m told by the backend folks that there are ongoing database problems, and the repair script requires that the blogs be taken offline, so they’re waiting until //build is over.

  5. Martin Bonner says:

    Why didn’t IIDFromString and CLSIDFromString move into rpcrt4? Were people doing LoadLibrary on OLE32 and GetProcAddress?

    1. Ron O says:

      That’s similar to what I was thinking: Why weren’t they moved to an even lower level library called by both ole32 and rpcrt4? Even if there are/were compatibility reasons for keeping the method signatures in ole32, it (ole32) could just forward on to the new component.

      1. Darran Rowe says:

        My thoughts is that because of the subtle differences, it couldn’t be a forwarded directly. The obvious thing being the one in rpcrt4 doesn’t like the braces around the uuid, but the ones in ole32 do.
        But that also doesn’t mean that ole32 didn’t start using the function in rpcrt4. In fact, if you look at the imports for ole32, then you should find it.
        21A UuidFromStringW
        I found that after doing a dumpbin on ole32 on my system (Windows 10 November update).
        To me, one possible way of implementing the ole32 functions is to lop off the braces and then call UuidFromString in rpcrt4. Of course, since CLSIDFromString also needed to do the registry lookup when someone passed in a ProgId, then it wasn’t just a call into UuidFromString.

      2. Darran Rowe says:

        Forgot to mention, the reason why these probably didn’t move is that they were intended to only be used with COM/OLE2. You can really see that with CLSIDFromString where it also does a lookup for a ProgId, which isn’t an RPC concept. So instead of trying to use the OLE functions, they just created a more general function.

  6. Damien says:

    Isn’t it obvious from the naming of the other DLLs? It was the version introduced with the 4-bit version of windows. :-)

Comments are closed.

Skip to main content