I'm writing a VC++/CLI
<-> C#
interface for a small unmanaged library. This library uses and implements WINAPI methods, so it mainly uses constructs as
DWORD getResult(__out LPWSTR* result);
Which means it does not return the requested result, but a statuscode, and the requested result is passed in the output parameter.
In C#, it seems, I have (at least) two ways of writing the interface:
UInt32 getResult(String^% result);
String^ getResult();
throwing an (e.g.) Win32Exception
when the statuscode of the managed call is non-zero (wrapping the statuscode in its NativeErrorCode
member) (as shown e.g. here: Throwing a Win32Exception )Of course this would not be that simple in case of multi-output functions, but let's say I don't care about them.
As I'm more used to OOP than to the VC++ style of coding, I would prefer option 2. However, I'm not sure if there aren't reasons that would render that a bad design choice (or if there isn't a third, even better way).
This is very much a matter of opinion--discussions about exception policy can go on forever.
I think you should mostly think about your framework's audience. If they're already accustomed to your unmanaged library then they might prefer the "dumb transpile" approach.
But if your users are typical C# developers then they'll expect #2, so that's what I'll cover from here on. A C# developer doesn't care that you're wrapping a native library and will just want your library to behave like every other .NET library.
So, assuming you go with #2, the Framework Design Guidelines book is a great place to start thinking about your exception design. Some stripped down excerpts are available on MSDN:
As for using Win32Exception, I'd avoid it if possible (but I say that without knowing anything about your errors or how many of them you're dealing with). The problem is that it only provides your users with a generic Win32 error message along the lines of "Access denied" or "File not found", which is unpleasant to .NET developers because it provides minimal context (i.e., what file wasn't found??).
To summarize, I'd translate as many of your error codes as possible to standard System exceptions, and, if you have additional useful information that might help callers' error handling then feed that info into the existing System exceptions (or create your own custom exception types if you must). Only throw Win32Exception as a last resort.