You're right, it is generally a good idea to use messages for this. It is also better performance wise to keep all the dispatching in one place.
But I tried that at the very beginning and it was rather inconvenient since I had to drag defines to every place I want to send a message from. "WM_USER + 'R'" might have worked but it's worse than "WM_USER, 'R'" aesthetically. And there is an extra parameter anyway.
PostMessage is also better for writing things to the counters since it's asynchronous. But it doesn't work for reading. It's just more convenient to have one function do both but of course you can post messages too.
It's a silly tool anyway. Basically made of compromises.