Thread: Windows API functions and exceptions

  1. #1
    Ex scientia vera
    Join Date
    Sep 2007
    Posts
    477

    Windows API functions and exceptions

    When writing some code that uses the windows API heavily, I thought about creating an exception class that would give you extended error information on a function, using GetLastError and FormatMessage.

    However, there is one thing I'm not sure of: Can I guarantee that no windows API function is called that calls SetLastError in between throwing the exception and handling it?

    For what it's worth, I'm callin GetLastError() in the constructor of the exception class, and when I throw it, the code is pretty much like this:

    Code:
    if(WindowsAPIFunction() == BAD_RETURN_VALUE)
         throw winapi_exception("WindowsAPIFunction()");
    I know I can modify the constructor to take the last error code as parameter to the constructor, but it somewhat defeats the convenience of the class. It's supposed to do that stuff for you.

    Any input on this will be appreciated.
    "What's up, Doc?"
    "'Up' is a relative concept. It has no intrinsic value."

  2. #2
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    As long as you don't call other API functions before you handle the exception you should be fine. But I'm not so sure exceptions are the best way to handle this. Most Win32 API functions return HRESULTs which can then be dealt with, turned into error messages via the API, or returned back to the user. Not every API call failure is a critical error or worthy of an exception.

  3. #3
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Code:
    winapi_exception CreateWinAPIException( const char *msg )
    {
        return winapi_exception( msg, GetLastError() );
    }
    Then:

    Code:
    throw CreateWinAPIException("WinAPIFunction() failed");
    The exception needs a copy constructor for it to work.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  4. #4
    Ex scientia vera
    Join Date
    Sep 2007
    Posts
    477
    Thank you for the advice.

    Bubba: While I realize that not all windows API functions are failures, where I'm using the exception class, they are indeed failures.
    Either way, it has an extra member that gives you the error code, in case you would want to handle the error, although that might not be useful farther up the stack.

    Brewbuck: Would that actually be any different than just throwing it? If so, why? Is it because it isn't guaranteed that the object is actually constructed at the same time you throw? E.g., might it be constructed once the stack has been unwound and the catch is about to be 'executed' ?
    "What's up, Doc?"
    "'Up' is a relative concept. It has no intrinsic value."

  5. #5
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by IceDane View Post
    Brewbuck: Would that actually be any different than just throwing it? If so, why? Is it because it isn't guaranteed that the object is actually constructed at the same time you throw? E.g., might it be constructed once the stack has been unwound and the catch is about to be 'executed' ?
    After thinking about it I don't think what I wrote is any safer than just throwing a directly-constructed exception. If you want to force the chain of events maybe implement something like this:

    Code:
    inline void ThrowWin32Exception( const char *msg )
    {
        // Statement is sequence point -- GetLastError() is guaranteed to be called before the
        // throw process starts
        winapi_exception exception( msg, GetLastError() );
        throw exception;
    }
    Then use ThrowWin32Exception() instead of directly throwing?
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  6. #6
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Are you writing a multi-threaded program?
    If so, then I would guess you could have a race condition where SetLastError() gets called again before GetLastError(). I'm not sure how to fix that.
    "I am probably the laziest programmer on the planet, a fact with which anyone who has ever seen my code will agree." - esbo, 11/15/2008

    "the internet is a scary place to be thats why i dont use it much." - billet, 03/17/2010

  7. #7
    Ex scientia vera
    Join Date
    Sep 2007
    Posts
    477
    Quote Originally Posted by brewbuck View Post
    After thinking about it I don't think what I wrote is any safer than just throwing a directly-constructed exception. If you want to force the chain of events maybe implement something like this:

    Code:
    inline void ThrowWin32Exception( const char *msg )
    {
        // Statement is sequence point -- GetLastError() is guaranteed to be called before the
        // throw process starts
        winapi_exception exception( msg, GetLastError() );
        throw exception;
    }
    Then use ThrowWin32Exception() instead of directly throwing?
    Ah, yes, thank you. I can declare that as a static member function inside the class, I presume, so it wouldn't really 'break the convenience of using it' or the object hierarchy or whatever.
    But are you absolutely sure that it is indeed possible for something to happen between the throw statement and the actual construction of the object? Does the standard say anything about this?

    If this is what needs to be done, I'll do it, but I would really like some confirmation first.

    cpjust: Nope, not multi-threaded. I guess there's not much to do in that case.
    "What's up, Doc?"
    "'Up' is a relative concept. It has no intrinsic value."

  8. #8
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by cpjust View Post
    Are you writing a multi-threaded program?
    If so, then I would guess you could have a race condition where SetLastError() gets called again before GetLastError(). I'm not sure how to fix that.
    Each thread has its own error code. SetLastError() from one thread can't interfere with another.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  9. #9
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by IceDane View Post
    But are you absolutely sure that it is indeed possible for something to happen between the throw statement and the actual construction of the object? Does the standard say anything about this?
    I believe the order of construction of objects and temporaries would be as you expect, but in this case the runtime may be doing things behind the scenes in order to prepare to throw an exception. For instance allocating a block of memory where the exception will be constructed. I think it's unlikely that anything could go wrong during that process that wouldn't take down your whole program anyway, but it's good of you to be paranoid about it.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  10. #10
    Ex scientia vera
    Join Date
    Sep 2007
    Posts
    477
    Quote Originally Posted by brewbuck View Post
    I believe the order of construction of objects and temporaries would be as you expect, but in this case the runtime may be doing things behind the scenes in order to prepare to throw an exception. For instance allocating a block of memory where the exception will be constructed. I think it's unlikely that anything could go wrong during that process that wouldn't take down your whole program anyway, but it's good of you to be paranoid about it.
    Alright - thanks. I'll try the class out using various windows API functions, and if a single scenario doesn't turn out as I hope, I will use your inline way of doing it.

    Thanks for the advice.
    "What's up, Doc?"
    "'Up' is a relative concept. It has no intrinsic value."

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Google C++ Style Guide
    By Memloop in forum C++ Programming
    Replies: 9
    Last Post: 09-23-2009, 08:20 PM
  2. How properly inherit from template?
    By 6tr6tr in forum C++ Programming
    Replies: 118
    Last Post: 04-25-2008, 04:30 AM
  3. Exceptions and constructors
    By Mostly Harmless in forum C++ Programming
    Replies: 2
    Last Post: 06-12-2007, 11:20 AM
  4. Long-lasting objects that throw exceptions
    By drrngrvy in forum C++ Programming
    Replies: 7
    Last Post: 10-05-2006, 04:30 PM
  5. FILES in WinAPI
    By Garfield in forum Windows Programming
    Replies: 46
    Last Post: 10-02-2003, 06:51 PM