locked
Throw customized exception from C++ runtime component

    Question

  • http://msdn.microsoft.com/en-us/library/windows/apps/hh755825.aspx

    http://social.msdn.microsoft.com/Forums/en-US/winappswithhtml5/thread/6ab9c654-4511-4773-b8d3-041ff41d6354

    In the C++ runtime component, my code throws an Platform::Exception which takes a customized error code and a customized error message.

    ... ...
        if (ER_OK != status) {
            throw ref new Platform::Exception(0x80000000 | (int)(status), "Too long");
        }
    ... ...

    In C# code we catch the exception. It shows that:

    e = {System.Exception: The text associated with this error code could not be found.}

    It looks that I can get the customized error code = e.HResult, but I cannot get the customized error message. Instead, the e.Message = "The text associated with this error code could not be found".

    Is there any way to get the customized error message? If both Platform::COMException and Platform::Exception both only allows customized error code, what is the purpose of having both?


    Thursday, December 20, 2012 9:33 PM

Answers

  • Let me clarify.

    WinRT exceptions travel across the WinRT ABI *only* as HRESULTs. So passing additional state to your caller (like a message) is not possible.

    The string that Platform::Exception::CreateException accepts allows you to provide a custom explanation for the reason of the failure *to the debugger only*. Basically the string is meant to be seen only by the developers of the app consuming your component. You should not retrieve this string in code and display it to an user of your app.

    You will notice the same behavior in the Windows streams APIs -- if you get a E_ACCESSDENIED when trying to read a file (which would translate to Platform::AccessDeniedException^), when the debugger communicates the failure in VS via the First Chance Exception dialog in VS and/or the VS Output Window, in addition to the type name (AccessDeniedException), it will also show a customized string (different than the FormatMessage string for E_ACCESSDENIED) that details the conditions of the failure. With the additional string parameter in CreateException, we want to expose the same capability to C++/CX WinRT API authors.

    Hope this helps,
    Marian Luparu
    Visual C++


    Friday, December 21, 2012 7:04 PM

All replies

  •   

    I tried

      if (ER_OK != status) {
            throw Platform::Exception::CreateException(0x80000000 | (int)(status), "Too long");
        }

    The result is the same.

    Thursday, December 20, 2012 9:58 PM
  • Renjie:

    The Exception::Message property is readonly, which you can see for yourself in Object Browser in platform.winmd: Platform::String^ Message { get; } The purpose of the Message property is to display the system-supplied string that is produced by FormatMessage.  So in short, there is no way to provide a custom error string for a COMException.  However, if you define a custom HRESULT, then you presumably also know what it means and can use an app-defined string to output to the developer (or end-user) when the exception is handled. Also, as a general rule, exception messages, including Windows system messages, should not be shown to end users. For more info, see http://msdn.microsoft.com/en-us/library/windows/apps/hh699896.aspx


    Thursday, December 20, 2012 11:20 PM
  • Hi Michael,

    I understand what you mean. But I am still a bit confused by the API. If COMException is the only way for customized exception, then why Platform::Exception allows to construct exceptions with two arguments: a hresult code and a message string using either the constructor and CreateException().

    Friday, December 21, 2012 1:34 AM
  • Let me clarify.

    WinRT exceptions travel across the WinRT ABI *only* as HRESULTs. So passing additional state to your caller (like a message) is not possible.

    The string that Platform::Exception::CreateException accepts allows you to provide a custom explanation for the reason of the failure *to the debugger only*. Basically the string is meant to be seen only by the developers of the app consuming your component. You should not retrieve this string in code and display it to an user of your app.

    You will notice the same behavior in the Windows streams APIs -- if you get a E_ACCESSDENIED when trying to read a file (which would translate to Platform::AccessDeniedException^), when the debugger communicates the failure in VS via the First Chance Exception dialog in VS and/or the VS Output Window, in addition to the type name (AccessDeniedException), it will also show a customized string (different than the FormatMessage string for E_ACCESSDENIED) that details the conditions of the failure. With the additional string parameter in CreateException, we want to expose the same capability to C++/CX WinRT API authors.

    Hope this helps,
    Marian Luparu
    Visual C++


    Friday, December 21, 2012 7:04 PM
  • Marian, this does not seem to work:

     if (ret != SQLITE_OK) {
          sqlite3_close(sqlite);
          throw ref new Platform::COMException(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), dbPath);
        }

    All I see in the debugger is "

    0x80070002 - JavaScript runtime error: The system cannot find the file specified.
    WinRT information: The system cannot find the file specified.

    "

    This information is of course useless to the programmer, because it leaves out the most important information about *which* file was not found. I send this information to the COMException ctor though. So what am I missing?

    Why did MSFT decide to not use the standard IErrorInfo way to let programmers provide extended error informations for the JS Thread? And why do they offer an Exception ctor with a message String argument, yet never expose that to the calling code?

    Wednesday, March 20, 2013 10:16 AM
  • WinRT supports specifying a reason for the failure but that string will only be available to the debugger. C++/CX allows specifying the string as part of the exception constructor, but you will not be able to access that string in code when you consume the exception. This is intentional since the string will be empty if no debugger is attached (the WinRT system will transport the string only if the process is being debugged).

    The JS debugger however should be able to access that string and display it in the debugger window. Unfortunately, this is a bug in Win8 and something the team is looking at addressing in the next version (if you try a similar exercise from C++ or CLR, the First Change Exception dialog should correctly display the message). Thanks for notifying us of this bug.

    Marian

    Monday, April 08, 2013 8:53 PM
  • Marian,

    In tests I've just been doing, the same bug exists for Windows Phone C#/XAML solutions.

    if I have a C# app that calls a C++ component, and the component throws a custom exception, the error string only displays in the debugger if you have selected native debugging in the project properties of the C# (client) project. If you have managed debugging enabled, you don't see the error, message, which makes it difficult for devs who are trying to use your WinRT component to know why an exception was thrown by the component.


    Technical Evangelist, Microsoft DPE


    Friday, May 03, 2013 7:03 PM
  • Thanks for the team looking into it. To be honest I liked the old COM way of IErrorInfo much more as it could provide real useful information to the programmer as well as to the user. COMException not transfering the message over binary boundaries is making debugging apps that much harder. It would be so easy for the JS layer to convert the COMException into a JS native Error object, like it did in the past with IErrorInfo.

    Could we also just use IErrorInfo and raise a normal Win32 Exception instead of using the useless COMException?

    Monday, May 13, 2013 3:07 PM