If you think about a bit more...
The signature of GetClientRect is:
BOOL GetClientRect(HWND hWnd, LPRECT lpRect);
Where HWND is a window handle, and LPRECT a (long) pointer to a RECT.
(the long means nothing these days, but in Win16 times there were near and far pointers: LPSTR was equivalent to
char far *
, whereas now it's just
char*
)
The thing to notice is that both parameters are
passed by value, so GetClientRect gets a
copy of your pointer.
If GetClientRect was stupid enough to try and change the value, you wouldn't notice: the value of your pointer would be the same as before you made the call, which is of no use. You'd never see what they pointed at, and there would be a memory leak as you couldn't free the allocated memory it allocated later on.
If the function did allocate memory for you, it would get you to pass it the address of your variable. That way they can change your variable for you and everything works: you get the new value and can free the memory later.
1 2 3 4 5 6 7 8 9
|
LPRECT pRect = NULL;
BOOL GetClientRectWithNew(hWnd, &pRect);
// GetClientRectWithNew deferences your pointer and set it to point
// at the memory they allocated: *ppRect = <some memory>
// You use pRect...
delete pRect;
|
In C++ you could use a reference to a pointer for the second parameter, but most of the Win32 API is C, which doesn't know what a reference it.
Now the reason this approach is not used in general by the Win32 API is that the module calling new (which would be User32.dll, if this was what it did) and the module calling delete must be using the same C++ runtime. This isn't always the case, especially if components are upgraded separately (they can start off in step, but end up using different runtimes.
In the case where they do allocate memory for you, they also provide a function to free the memory. This allows the same DLL that allocated the memory to free it. But the approach that GetClientRect uses is safer for routine use as there's less chance of forgetting to free memory.
So, when you write a C style DLL function, you should avoid passing memory out of functions. If you do, you need to provide a corresponding free.
And for the same reason, C++ function which return things like std::strings and std::vectors can be a real problem when it comes to DLL versioning, C++ linkage and DLLs should be avoided as a rule (that is, unless the modules will always be updated together).