Archive for September, 2006

New device driver blog

Thursday, September 28th, 2006

It looks like there’s a new driver-related blog in the world. Peter has a pointer to new UMDF team member Ilias Tsigkogiannis’s newly started blog. Looks like it’s going to cover somewhat more introductory topics, at least at first.

Welcome to the blogosphere, Ilias!

UPDATE: Wow, sorry about the typo… it’s a blog, not a bog.

For the person who’s always out of disk space

Thursday, September 21st, 2006

This is amazing: a 12-disk SATA array for $840. I remember when I was shocked that it was feasible for me to build a 1TB server at the local parts store. Seems like yesterday.

It turns out that nobody knows how to use XHTML

Wednesday, September 20th, 2006

The Surfin’ Safari blog has a post by maciej pointing out that most people use XHTML wrong, including (in particular) almost everyone that displays the “Valid XHTML 1.0″ logo on their websites.

So what really determines if a document is HTML or XHTML? The one and only thing that controls whether a document is HTML or XHTML is the MIME type. If the document is served with a text/html MIME type, it is treated as HTML. If it is served as application/xhtml+xml or text/xml, it gets treated as XHTML. In particular, none of the following things will cause your document to be treated as XHTML:

  • Using an XHTML doctype declaration
  • Putting an XML declaration at the top
  • Using XHTML-specific syntax like self-closing tags
  • Validating it as XHTML

In fact, the vast majority of supposedly XHTML documents on the internet are served as text/html. Which means they are not XHTML at all, but actually invalid HTML that’s getting by on the error handling of HTML parsers.

The article concludes by recommending, essentially, that you write HTML 4.01 code and serve it up as text/html. Controversial advice, given what the Web Standards crowd has been saying about XHTML for a while. In light of the above, XHTML seems worse than useless (for the next decade anyway) – it’s actually causing the very compatibility problems that the WaSP people are trying to prevent. I’m curious to know what people like Molly Holzschlag have to say about this.

The article is worth a read. Don’t give up on it because of it’s very introductory-level first paragraph.

Positive Networks blog

Wednesday, September 20th, 2006

It had to happen eventually! My company, Positive Networks, finally has a blog. For those that don’t know, Positive Networks provides one of the coolest remote access services in the industry. We’re going to be blogging mostly about VPN-related stuff and Positive corporate happenings. Stop by and say hello.

It’s funny to see what posts resonate

Wednesday, September 20th, 2006

Nobody is a good critic of his or her own work, but I thought I had at least a reasonable idea of what people like to read on this site. However, according to the site traffic data, the post about the Christmas presents seems to be one of the most popular ever. Several people (including a couple of commenters) have asked me about the Private Dancer shirt. (And no, I don’t know where to get one; sorry!)

The beauty of C99

Tuesday, September 19th, 2006

With the advent of the new WDK compilers and Visual C++ 2005, we are now in a happy world of C99 standards compliance. Some of C99 is not particularly useful to me; I can ignore most of the math improvements, for example. Other things, like _Bool, are basically irrelevant since they’ve long been replaced by OS-defined types.

One new feature of C99 is the ability to write variadic macros. Everyone has written (or read) code similar to this:

#define DBGPRINT(x) printf x;
...
DBGPRINT(("Hello world\n"));

I actually like to add automatic newline addition, file/line information, and other goodies to my debug print macro, so I wind up needing several lines:

#define DBGPRINT(x) \
{ \
	...
	printf x; \
	printf("\\n"); \
}

Things get even more complicated if you want to pass arguments to a function like fprintf() – For example, I like my debug strings to go to stderr, so I would write fprintf(stderr, ...). That needs a helper function.

Using C99 variadic macros, you can avoid all of these problems:

#define DBGPRINT(...) fprintf(stderr, "%s\\n", __VA_ARGS__);
...
DBGPRINT("hello world");

In fact, you can do even more. Here are some examples from the C99 Draft Standard:

#define debug(...) fprintf(stderr, __VA_ARGS__)

#define showlist(...) puts(#__VA_ARGS__)

#define report(test, ...) ((test)?puts(#test):\
	printf(__VA_ARGS__))

int x = 2, y = 1;

debug("Flag");
debug("X = %d\\n", x);

showlist(The first, second, and third items.);

report(x>y, "x is %d but y is %d", x, y);

C99 variadic macros are supported by the VS 2005 compiler and by the WDK compiler, as well as by GCC, even when building C++ code.

Channel9 Interview with Peter Wieland

Monday, September 18th, 2006

There’s a video of Peter Wieland up on Chanel 9. Peter is the development lead for UMDF and a regular contributor to the newsgroups and mailing lists.

There are also videos of Doron Holan discussing KMDF and Donn Terry discussing PreFAST, while you’re at it. I got the chance to meet Donn at the last MVP summit, and was really impressed. He’s exactly the guy you’d want working on PreFAST.

Good to see Channel 9 doing well post-Scoble.

When you can’t follow the API

Saturday, September 16th, 2006

So now that we’re all convinced that the best thing to do is to pick types by following the API, let’s take a look at a place or two where that’s impossible to do right.

There are a great many reasons that I love to code to Win32. For instance, you’ve gotta hand it to an API that includes things like three-valued BOOLs. Here’s another special one.

Say you’re trying to play by the rules, so you choose to call SetWindowLongPtr() and GetWindowLongPtr() for the sake of future portability. You see that GetWindowLongPtr() returns a LONG_PTR. So, you write:

char *x = reinterpret_cast(GetWindowLongPtr(...));

…and you get this:

warning C4312: 'reinterpret_cast' : conversion from 'LONG'
to 'char *' of greater size

What gives? Well, if you open up WinUser.h in the PSDK (Server 2003 R2 in my case), you will find that it only actually return ULONG_PTR if _Win64 is defined. Otherwise, it’s defined back to GetWindowLong(), which of course returns a LONG.

So, it turns out that there’s no way to avoid a compiler warning without writing non-portable code (by casting a pointer to a 32-bit value), which is exactly what we’re trying to avoid.

There is a solution, though, although it’s not particularly elegant. You can do a one-line warning suppression like so:

#pragma warning(suppress:4312)
char *x = reinterpret_cast(GetWindowLongPtr(...));

The suppress pragma above disables the warning for the following source file line only. A couple of notes on that pragma: First, it is documented to only work with analysis (i.e. PREfast), but it actually works perfectly in my VC8 compiler too. Also, it is only for the following source line, not statement, so if you have multi-line statements, you have to put the pragma in the middle like so:

origWindowProc = reinterpret_cast(SetWindowLongPtr(
		animControl,
		GWLP_WNDPROC,
		#pragma warning(suppress:4244)
		#pragma warning(suppress:4312)
		reinterpret_cast(subclassAnimProcSt)));

You can also only disable one warning at a time with that pragma. Follow the example above to disable multiple warnings at once.

In the end, I believe it’s worthwhile to have warning-free code at the highest compiler warning levels. If you had written code using the types dictated by the standard C library (i.e. using size_t, ptrdiff_t, and so on), you would have found that the port to 64-bit code was a lot easier to deal with, and (in trivial cases) even just a recompile. Additionally, it makes it easier to spot warnings when they do happen, and it makes it easier to use static analysis tools like PREfast and PC-Lint.

API-driven types

Friday, September 15th, 2006

Pop quiz: what’s the return type of strlen()? (Ignore the related question of why use strlen()? for the moment.)

In fairness, it depends on who you ask. Recent Microsoft implementations return size_t, and POSIX agrees.

9 out of 10 dentists (and at least one blogger) agree that it is better to limit the use of casting in your code. If you’re going to do that, you’ll find out early on that you have to match the types your program uses to the types that your APIs use. Otherwise you will create porting difficulties and compiler warnings, which usually lead right back to casts.

In fact, the process of type selection is very different if you do things this way: you select variable types based on what the APIs you use expect.

In the case of strlen() above, you’ll get a complier warning if you try to use an unsigned long (for example) as the return type (under /Wp64 anyway), because on 64-bit Windows, size_t (strlen()’s real return type) is 64 bits, and unsigned long is 32 bits.

Win32 loves to use DWORDs everywhere, which is well enough as long as your types match, and as long as you keep in mind that the interface between things like strlen() and Win32 necessarily involves casting and range limitations. Also, doing things like forcing HANDLEs into DWORDs is obviously not a good idea.

In the end, porting code to be type-correct is about as much fun as porting C++ code to be const correct. It’s something that’s dramatically easier to do at design time. On the flip side, actually doing a port such as this can lead to a better understanding of any range issues that are intrinsic to the code (such as the CRT <-> Win32 interface I mentioned), and it’s great for finding bugs and as an in-depth code review. If you happen to enjoy that kind of thing, anyway.

My advice is to be precise from the outset about matching your types to the types expected and returned by the APIs you’re using.

Prediction update

Thursday, September 14th, 2006

My prediction appears to be wrong. But not by much. I’m going to keep it secret a while longer just to make sure.