Fun Fact: the Windows API uses HRESULT to return success/failure of a particular call. The COM API uses the same. VB6 was the first platform by Microsoft to implement exceptions throughout the code (that I'm aware of)... and beneath it, it used COM. So that means that VB6 generated an exception whenever a COM status code returned E_FAIL or similar, and didn't if it was classed as SUCCESS (eg S_OK, S_FALSE, etc).
The original .NET implementors clearly used the VB6 model when developing the codebase (it was nearly a one-to-one match from VB6 to VB.NET) and very easy to port over.
That said, when I read the article, "Exceptions are the primary means of reporting errors in Frameworks" vs "Do not use exceptions for the normal flow of control, if possible" I see this never ending problem appear. Most things we do in our programs use Frameworks, which throw exceptions, which may or may not actually be exceptional for the case of the calling function. Nevertheless, it must be handled.
However, back in the C++ Win API and COM world, you could easily use: `HRESULT hr= SomeFunc(); if (FAILED(hr)) return hr;` to bubble up a failure code, or if you handled it in other ways, you can safely ignore the return code and continue on. In the .NET world exceptions must always be handled otherwise they ripple all the way up and end up as a crashed application. Of course, some think this is a good design principle to have it so: Others are not so convinced.
And so, the debate continues.