RegQueryValueEx – how not to write a function document

I’ve said before that I think some of our problems with unsecure development can be addressed by making documentation better.

[Tech writers, please note - I don't mean this to imply that you are responsible for all of these ills, but I do think that a little more effort and care would prevent developers from making stupid and possibly dangerous mistakes that your documentation was originally designed to prevent.]

Take a look at the documentation of RegQueryValueEx – but before you go there, imagine you’re a developer, and your job is to query a value whose size you don’t know.

So, blah, blah, blah, “lpData … can be NULL if the data is not required” – okay, let’s set lpData to NULL.

Blah blah, more blah, “lpcbData … When the function returns, this variable contains the size of the data copied to lpData … if the buffer specified by lpData parameter is not large enough to hold the data, the function returns ERROR_MORE_DATA and stores the required buffer size in the variable pointed to by lpcbData”.

We have the answer we’re looking for, so we stop reading and go write some code. Just for a check, we look at Return Values:

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is a system error code.

If the lpData buffer is too small to receive the data, the function returns ERROR_MORE_DATA.

Sounds like we have our answer – pass lpData as NULL, and expect ERROR_MORE_DATA to be returned, then we can use the value.

We go back to the documentation.

Oh – we stopped reading too soon.

“If lpData is NULL, and lpcbData is non-NULL, the function returns ERROR_SUCCESS and stores the size of the data, in bytes, in the variable pointed to by lpcbData.”

Woah – that’s counter-intuitive and unexpected.

[Read the paragraph after that for another couple of counter-intuitive and surprising behaviours.]

How would you write this behaviour as a program?

Well, if you were writing a maintainable program, you’d do something like this:

if (lpcbData == NULL)
    return ERROR_SUCCESS;
if (hKey is in HKEY_PERFORMANCE_DATA)
{
    *lpcbData = random value;
    return ERROR_MORE_DATA;
}
if ( lpData == NULL )
{
    *lpcbData = size of data;
    return ERROR_SUCCESS;
}
if (size of data < *lpcbData)
{
    *lpcbData = size of data;
    return ERROR_MORE_DATA;
}
*lpcbData = size of data;
… read data into lpData …
return ERROR_SUCCESS;

But that’s the exact opposite of the way in which the documentation is written. Our code goes from most specific to least specific, with the general situation at the end; the documentation starts with the general situation and ends with some specifics. As a result, if you’re a programmer who proceeds a little like a computer program, you’re going to make a mistake with this kind of documentation, and if you recognise that mistake, you’re going to make another mistake when you’re fixing it, etc, etc.

Trouble is, I’m not sure how you could rewrite the documentation so that it would read pleasantly, but still answer the problem of programmers reading the documentation with a scenario in their minds.

One thought on “RegQueryValueEx – how not to write a function document”

  1. MSDN sucks sometimes and they don’t write the proper documentation, for example, they say that certain API’s only exist on Win2k / XP / Vista when they are really on Windows 95 / 98 / ME, etc..

    The registry functions always give new programmers trouble because they are unlike most API and act in dumb ways.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>