Turning API Errors into Basic Errors


DevX Home    Today's Headlines   Articles Archive   Tip Bank   Forums   

Results 1 to 15 of 15

Thread: Turning API Errors into Basic Errors

  1. #1
    Jim Pragit Guest

    Turning API Errors into Basic Errors


    I was searching thru the MSDN, and I happened to stumble upon a section called
    "Turning API Errors into Basic Errors" from Bruce McKinney's Hardcore VB
    book. In it, he demonstrates how errors from API calls can be raised to
    calling routines via the Err.Raise method (example code follows). I was
    wondering how many people follow this strategy and how often. Usually I
    don't expect an API to fail so I rarely even check return values, let alone
    raise them back as errors to the calling routines. This method has always
    worked for me but now that I think about, it seems kind of foolish of me
    to ignore return values. On the other hand, I honestly cannot think of any
    situation where this lack of error handling has hurt me.

    - Jim

    c = GetTempPath(cMaxPath, sRet)
    If c = 0 Then ApiRaise Err.LastDllError

    Sub ApiRaise(ByVal e As Long)
    Err.Raise vbObjectError + 29000 + e, _
    App.ExeName & “.Windows”, ApiError(e)
    End Sub

    Function ApiError(ByVal e As Long) As String
    Dim s As String, c As Long
    s = String(256, 0)
    c = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM Or _
    FORMAT_MESSAGE_IGNORE_INSERTS, _
    pNull, e, 0&, s, Len(s), ByVal pNull)
    If c Then ApiError = Left$(s, c)
    End Function


  2. #2
    Mark Alexander Bertenshaw Guest

    Re: Turning API Errors into Basic Errors

    Jim -

    Basically, it is worth checking return values when it is possible that a
    memory allocation might fail, and when a device might not be available.

    --

    ---------------------------------------
    Mark Alexander Bertenshaw
    Programmer/Analyst
    Prime Response
    Brentford
    UK
    "Jim Pragit" <James.Pragit@BakerNet.com> wrote in message
    news:38f60cd8$1@news.devx.com...
    >
    > I was searching thru the MSDN, and I happened to stumble upon a section

    called
    > "Turning API Errors into Basic Errors" from Bruce McKinney's Hardcore VB
    > book. In it, he demonstrates how errors from API calls can be raised to
    > calling routines via the Err.Raise method (example code follows). I was
    > wondering how many people follow this strategy and how often. Usually I
    > don't expect an API to fail so I rarely even check return values, let

    alone
    > raise them back as errors to the calling routines. This method has always
    > worked for me but now that I think about, it seems kind of foolish of me
    > to ignore return values. On the other hand, I honestly cannot think of

    any
    > situation where this lack of error handling has hurt me.
    >
    > - Jim
    >
    > c = GetTempPath(cMaxPath, sRet)
    > If c = 0 Then ApiRaise Err.LastDllError
    >
    > Sub ApiRaise(ByVal e As Long)
    > Err.Raise vbObjectError + 29000 + e, _
    > App.ExeName & ".Windows", ApiError(e)
    > End Sub
    >
    > Function ApiError(ByVal e As Long) As String
    > Dim s As String, c As Long
    > s = String(256, 0)
    > c = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM Or _
    > FORMAT_MESSAGE_IGNORE_INSERTS, _
    > pNull, e, 0&, s, Len(s), ByVal pNull)
    > If c Then ApiError = Left$(s, c)
    > End Function
    >




  3. #3
    Mark Alexander Bertenshaw Guest

    Re: Turning API Errors into Basic Errors

    Jim -

    Basically, it is worth checking return values when it is possible that a
    memory allocation might fail, and when a device might not be available.

    --

    ---------------------------------------
    Mark Alexander Bertenshaw
    Programmer/Analyst
    Prime Response
    Brentford
    UK
    "Jim Pragit" <James.Pragit@BakerNet.com> wrote in message
    news:38f60cd8$1@news.devx.com...
    >
    > I was searching thru the MSDN, and I happened to stumble upon a section

    called
    > "Turning API Errors into Basic Errors" from Bruce McKinney's Hardcore VB
    > book. In it, he demonstrates how errors from API calls can be raised to
    > calling routines via the Err.Raise method (example code follows). I was
    > wondering how many people follow this strategy and how often. Usually I
    > don't expect an API to fail so I rarely even check return values, let

    alone
    > raise them back as errors to the calling routines. This method has always
    > worked for me but now that I think about, it seems kind of foolish of me
    > to ignore return values. On the other hand, I honestly cannot think of

    any
    > situation where this lack of error handling has hurt me.
    >
    > - Jim
    >
    > c = GetTempPath(cMaxPath, sRet)
    > If c = 0 Then ApiRaise Err.LastDllError
    >
    > Sub ApiRaise(ByVal e As Long)
    > Err.Raise vbObjectError + 29000 + e, _
    > App.ExeName & ".Windows", ApiError(e)
    > End Sub
    >
    > Function ApiError(ByVal e As Long) As String
    > Dim s As String, c As Long
    > s = String(256, 0)
    > c = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM Or _
    > FORMAT_MESSAGE_IGNORE_INSERTS, _
    > pNull, e, 0&, s, Len(s), ByVal pNull)
    > If c Then ApiError = Left$(s, c)
    > End Function
    >




  4. #4
    Jim Pragit James.Pragit Guest

    Re: Turning API Errors into Basic Errors


    Mark,
    Thanks for the tips, those are good things to keep in mind. I take it
    from the lack of response, that not many people follow Bruce McKinney's suggestion.

    - Jim

    "Mark Alexander Bertenshaw" <Mark.Bertenshaw@virgin.net> wrote:
    >Jim -
    >
    >Basically, it is worth checking return values when it is possible that a
    >memory allocation might fail, and when a device might not be available.
    >
    >--
    >
    >---------------------------------------
    >Mark Alexander Bertenshaw
    >Programmer/Analyst
    >Prime Response
    >Brentford
    >UK
    >"Jim Pragit" <James.Pragit@BakerNet.com> wrote in message
    >news:38f60cd8$1@news.devx.com...
    >>
    >> I was searching thru the MSDN, and I happened to stumble upon a section

    >called
    >> "Turning API Errors into Basic Errors" from Bruce McKinney's Hardcore

    VB
    >> book. In it, he demonstrates how errors from API calls can be raised

    to
    >> calling routines via the Err.Raise method (example code follows). I was
    >> wondering how many people follow this strategy and how often. Usually

    I
    >> don't expect an API to fail so I rarely even check return values, let

    >alone
    >> raise them back as errors to the calling routines. This method has always
    >> worked for me but now that I think about, it seems kind of foolish of

    me
    >> to ignore return values. On the other hand, I honestly cannot think of

    >any
    >> situation where this lack of error handling has hurt me.
    >>
    >> - Jim
    >>
    >> c = GetTempPath(cMaxPath, sRet)
    >> If c = 0 Then ApiRaise Err.LastDllError
    >>
    >> Sub ApiRaise(ByVal e As Long)
    >> Err.Raise vbObjectError + 29000 + e, _
    >> App.ExeName & ".Windows", ApiError(e)
    >> End Sub
    >>
    >> Function ApiError(ByVal e As Long) As String
    >> Dim s As String, c As Long
    >> s = String(256, 0)
    >> c = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM Or _
    >> FORMAT_MESSAGE_IGNORE_INSERTS, _
    >> pNull, e, 0&, s, Len(s), ByVal pNull)
    >> If c Then ApiError = Left$(s, c)
    >> End Function



  5. #5
    Jim Pragit James.Pragit Guest

    Re: Turning API Errors into Basic Errors


    Mark,
    Thanks for the tips, those are good things to keep in mind. I take it
    from the lack of response, that not many people follow Bruce McKinney's suggestion.

    - Jim

    "Mark Alexander Bertenshaw" <Mark.Bertenshaw@virgin.net> wrote:
    >Jim -
    >
    >Basically, it is worth checking return values when it is possible that a
    >memory allocation might fail, and when a device might not be available.
    >
    >--
    >
    >---------------------------------------
    >Mark Alexander Bertenshaw
    >Programmer/Analyst
    >Prime Response
    >Brentford
    >UK
    >"Jim Pragit" <James.Pragit@BakerNet.com> wrote in message
    >news:38f60cd8$1@news.devx.com...
    >>
    >> I was searching thru the MSDN, and I happened to stumble upon a section

    >called
    >> "Turning API Errors into Basic Errors" from Bruce McKinney's Hardcore

    VB
    >> book. In it, he demonstrates how errors from API calls can be raised

    to
    >> calling routines via the Err.Raise method (example code follows). I was
    >> wondering how many people follow this strategy and how often. Usually

    I
    >> don't expect an API to fail so I rarely even check return values, let

    >alone
    >> raise them back as errors to the calling routines. This method has always
    >> worked for me but now that I think about, it seems kind of foolish of

    me
    >> to ignore return values. On the other hand, I honestly cannot think of

    >any
    >> situation where this lack of error handling has hurt me.
    >>
    >> - Jim
    >>
    >> c = GetTempPath(cMaxPath, sRet)
    >> If c = 0 Then ApiRaise Err.LastDllError
    >>
    >> Sub ApiRaise(ByVal e As Long)
    >> Err.Raise vbObjectError + 29000 + e, _
    >> App.ExeName & ".Windows", ApiError(e)
    >> End Sub
    >>
    >> Function ApiError(ByVal e As Long) As String
    >> Dim s As String, c As Long
    >> s = String(256, 0)
    >> c = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM Or _
    >> FORMAT_MESSAGE_IGNORE_INSERTS, _
    >> pNull, e, 0&, s, Len(s), ByVal pNull)
    >> If c Then ApiError = Left$(s, c)
    >> End Function



  6. #6
    Colin McGuigan Guest

    Re: Turning API Errors into Basic Errors

    Jim Pragit James.Pragit wrote in message <38f74486$1@news.devx.com>...
    >
    >Mark,
    > Thanks for the tips, those are good things to keep in mind. I take it
    >from the lack of response, that not many people follow Bruce McKinney's

    suggestion.
    >
    >- Jim
    >


    I tend to encapsulate my API calls, and check their return values for errors
    on a regular basis actually. If I do get a non-expected return value, I'll
    call FormatMessage and GetLastError (I use a win.tlb and my own typelib for
    API calls, so GetLastError is actually useful).

    I've done this ever since I had a program reading from the registry to get
    modem information, and it failed on non-administrator accounts because those
    keys were read-only, but I was requesting read/write permissions. Since I
    wasn't doing any error checking then, all I knew was there was a problem I
    couldn't reproduce (having administrator rights) with getting the registry
    handles. After debugging it, putting in error checks to the API became
    second nature.


    --
    Colin McGuigan




  7. #7
    Colin McGuigan Guest

    Re: Turning API Errors into Basic Errors

    Jim Pragit James.Pragit wrote in message <38f74486$1@news.devx.com>...
    >
    >Mark,
    > Thanks for the tips, those are good things to keep in mind. I take it
    >from the lack of response, that not many people follow Bruce McKinney's

    suggestion.
    >
    >- Jim
    >


    I tend to encapsulate my API calls, and check their return values for errors
    on a regular basis actually. If I do get a non-expected return value, I'll
    call FormatMessage and GetLastError (I use a win.tlb and my own typelib for
    API calls, so GetLastError is actually useful).

    I've done this ever since I had a program reading from the registry to get
    modem information, and it failed on non-administrator accounts because those
    keys were read-only, but I was requesting read/write permissions. Since I
    wasn't doing any error checking then, all I knew was there was a problem I
    couldn't reproduce (having administrator rights) with getting the registry
    handles. After debugging it, putting in error checks to the API became
    second nature.


    --
    Colin McGuigan




  8. #8
    Jim Pragit Guest

    Re: Turning API Errors into Basic Errors


    What intrigued me about Bruce McKinney's code was the prospect of making APIs
    work like VB statements. That is, instead of returning an error code, they
    would raise a run-time error. Right now, I usually ignore the return value.
    So I usually call an API like this:

    Call SHFileOperation(udtSHFileOp)

    If this API returned an error code, I would be none the wiser. Alternatively,
    I could code this:

    lngReturn = SHFileOperation(udtSHFileOp)
    If lngReturn <> 0 Then
    'do something to handle error
    End If

    However, I'm not too crazy about constantly checking return codes like this.
    (I know this is just a matter of opinion but to me it obfuscates the routine's
    logic.) But what if I coded something like this:

    CallAPI SHFileOperation(udtSHFileOp)

    And then in some standard module, I had these two utility routines:

    Public Sub CallAPI(ByVal ErrorCode As Long)
    '*****************************************************************
    '* This routine is designed to turn a Win32 API error code into *
    '* a Visual Basic run-time error. *
    '*****************************************************************
    Const WIN_ERROR_BASE As Long = 29000 'Bruce McKinney's error base
    Dim lngErrNbr As Long
    Dim strErrMsg As String

    If ErrorCode <> 0 Then
    lngErrNbr = vbObjectError + WIN_ERROR_BASE + ErrorCode
    strErrMsg = APIErrorMsg(ErrorCode)
    Err.Raise lngErrNbr, "Windows", strErrMsg
    End If

    End Sub

    Private Function APIErrorMsg(ByVal ErrorCode As Long) As String
    '*****************************************************************
    '* This function will return an error message given the return *
    '* code from a Windows API call. *
    '*****************************************************************
    Const FORMAT_MESSAGE_IGNORE_INSERTS As Long = 512
    Const FORMAT_MESSAGE_FROM_SYSTEM As Long = 4096
    Dim strMsg As String
    Dim lngErrorCode As Long

    strMsg = Space$(256)

    lngErrorCode = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM Or _
    FORMAT_MESSAGE_IGNORE_INSERTS, 0&, ErrorCode, 0&, _
    strMsg, Len(strMsg), 0&)

    If lngErrorCode <> 0 Then
    APIErrorMsg = Left$(strMsg, lngErrorCode)
    End If

    End Function

    This would allow me to call APIs almost the same way I do now, yet provide
    much improved error handling. And if I decide to go back and change all
    my existing code to use this strategy, I need only change all my Call statements
    to CallAPI. Any and all thoughts welcome.

    - Jim

  9. #9
    Jim Pragit Guest

    Re: Turning API Errors into Basic Errors


    What intrigued me about Bruce McKinney's code was the prospect of making APIs
    work like VB statements. That is, instead of returning an error code, they
    would raise a run-time error. Right now, I usually ignore the return value.
    So I usually call an API like this:

    Call SHFileOperation(udtSHFileOp)

    If this API returned an error code, I would be none the wiser. Alternatively,
    I could code this:

    lngReturn = SHFileOperation(udtSHFileOp)
    If lngReturn <> 0 Then
    'do something to handle error
    End If

    However, I'm not too crazy about constantly checking return codes like this.
    (I know this is just a matter of opinion but to me it obfuscates the routine's
    logic.) But what if I coded something like this:

    CallAPI SHFileOperation(udtSHFileOp)

    And then in some standard module, I had these two utility routines:

    Public Sub CallAPI(ByVal ErrorCode As Long)
    '*****************************************************************
    '* This routine is designed to turn a Win32 API error code into *
    '* a Visual Basic run-time error. *
    '*****************************************************************
    Const WIN_ERROR_BASE As Long = 29000 'Bruce McKinney's error base
    Dim lngErrNbr As Long
    Dim strErrMsg As String

    If ErrorCode <> 0 Then
    lngErrNbr = vbObjectError + WIN_ERROR_BASE + ErrorCode
    strErrMsg = APIErrorMsg(ErrorCode)
    Err.Raise lngErrNbr, "Windows", strErrMsg
    End If

    End Sub

    Private Function APIErrorMsg(ByVal ErrorCode As Long) As String
    '*****************************************************************
    '* This function will return an error message given the return *
    '* code from a Windows API call. *
    '*****************************************************************
    Const FORMAT_MESSAGE_IGNORE_INSERTS As Long = 512
    Const FORMAT_MESSAGE_FROM_SYSTEM As Long = 4096
    Dim strMsg As String
    Dim lngErrorCode As Long

    strMsg = Space$(256)

    lngErrorCode = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM Or _
    FORMAT_MESSAGE_IGNORE_INSERTS, 0&, ErrorCode, 0&, _
    strMsg, Len(strMsg), 0&)

    If lngErrorCode <> 0 Then
    APIErrorMsg = Left$(strMsg, lngErrorCode)
    End If

    End Function

    This would allow me to call APIs almost the same way I do now, yet provide
    much improved error handling. And if I decide to go back and change all
    my existing code to use this strategy, I need only change all my Call statements
    to CallAPI. Any and all thoughts welcome.

    - Jim

  10. #10
    Colin McGuigan Guest

    Re: Turning API Errors into Basic Errors

    Jim Pragit wrote in message <38f764e1$1@news.devx.com>...
    >
    >What intrigued me about Bruce McKinney's code was the prospect of making

    APIs
    >work like VB statements. That is, instead of returning an error code, they
    >would raise a run-time error. Right now, I usually ignore the return

    value.
    > So I usually call an API like this:
    >
    > Call SHFileOperation(udtSHFileOp)
    >
    >If this API returned an error code, I would be none the wiser.

    Alternatively,
    >I could code this:
    >
    > lngReturn = SHFileOperation(udtSHFileOp)
    > If lngReturn <> 0 Then
    > 'do something to handle error
    > End If
    >
    >However, I'm not too crazy about constantly checking return codes like

    this.
    >(I know this is just a matter of opinion but to me it obfuscates the

    routine's
    >logic.) But what if I coded something like this:


    <snip code>

    >This would allow me to call APIs almost the same way I do now, yet provide
    >much improved error handling. And if I decide to go back and change all
    >my existing code to use this strategy, I need only change all my Call

    statements
    >to CallAPI. Any and all thoughts welcome.
    >
    >- Jim


    The problem with this idea as provided is that you've got a severe lack of
    standardization amongst the APIs. For example, for a number of them, a
    non-zero value does indeed indicate an error code. However, another large
    majority use a zero value to indicate an error, and a non-zero value to
    indicate success (eg, GetDiskFreeSpace[Ex], GetComputerName, etc), and a
    number of others use the return value to return a handle or a length of a
    string (eg, GetPrivateProfileString).

    You could, of course, have two subroutines, one for '0 = success' and one
    for '0 = error'...but that gets into problems of it's own. This is why I
    tend to encapsulate my API calls.

    --
    Colin McGuigan




  11. #11
    Colin McGuigan Guest

    Re: Turning API Errors into Basic Errors

    Jim Pragit wrote in message <38f764e1$1@news.devx.com>...
    >
    >What intrigued me about Bruce McKinney's code was the prospect of making

    APIs
    >work like VB statements. That is, instead of returning an error code, they
    >would raise a run-time error. Right now, I usually ignore the return

    value.
    > So I usually call an API like this:
    >
    > Call SHFileOperation(udtSHFileOp)
    >
    >If this API returned an error code, I would be none the wiser.

    Alternatively,
    >I could code this:
    >
    > lngReturn = SHFileOperation(udtSHFileOp)
    > If lngReturn <> 0 Then
    > 'do something to handle error
    > End If
    >
    >However, I'm not too crazy about constantly checking return codes like

    this.
    >(I know this is just a matter of opinion but to me it obfuscates the

    routine's
    >logic.) But what if I coded something like this:


    <snip code>

    >This would allow me to call APIs almost the same way I do now, yet provide
    >much improved error handling. And if I decide to go back and change all
    >my existing code to use this strategy, I need only change all my Call

    statements
    >to CallAPI. Any and all thoughts welcome.
    >
    >- Jim


    The problem with this idea as provided is that you've got a severe lack of
    standardization amongst the APIs. For example, for a number of them, a
    non-zero value does indeed indicate an error code. However, another large
    majority use a zero value to indicate an error, and a non-zero value to
    indicate success (eg, GetDiskFreeSpace[Ex], GetComputerName, etc), and a
    number of others use the return value to return a handle or a length of a
    string (eg, GetPrivateProfileString).

    You could, of course, have two subroutines, one for '0 = success' and one
    for '0 = error'...but that gets into problems of it's own. This is why I
    tend to encapsulate my API calls.

    --
    Colin McGuigan




  12. #12
    Jim Pragit Guest

    Re: Turning API Errors into Basic Errors


    Good point. I took another look at Bruce's code and he pretty much uses the
    two subroutines approach. (Actually, he inlines the error handling when 0
    indicates failure). I'm not sure if he follows this strategy throughout
    the whole book or just for this section on API error handling.

    - Jim

    "Colin McGuigan" <colin@chicor.com> wrote:
    >The problem with this idea as provided is that you've got a severe lack

    of
    >standardization amongst the APIs. For example, for a number of them, a
    >non-zero value does indeed indicate an error code. However, another large
    >majority use a zero value to indicate an error, and a non-zero value to
    >indicate success (eg, GetDiskFreeSpace[Ex], GetComputerName, etc), and a
    >number of others use the return value to return a handle or a length of

    a
    >string (eg, GetPrivateProfileString).
    >
    >You could, of course, have two subroutines, one for '0 = success' and one
    >for '0 = error'...but that gets into problems of it's own. This is why

    I
    >tend to encapsulate my API calls.
    >--
    >Colin McGuigan



  13. #13
    Jim Pragit Guest

    Re: Turning API Errors into Basic Errors


    Good point. I took another look at Bruce's code and he pretty much uses the
    two subroutines approach. (Actually, he inlines the error handling when 0
    indicates failure). I'm not sure if he follows this strategy throughout
    the whole book or just for this section on API error handling.

    - Jim

    "Colin McGuigan" <colin@chicor.com> wrote:
    >The problem with this idea as provided is that you've got a severe lack

    of
    >standardization amongst the APIs. For example, for a number of them, a
    >non-zero value does indeed indicate an error code. However, another large
    >majority use a zero value to indicate an error, and a non-zero value to
    >indicate success (eg, GetDiskFreeSpace[Ex], GetComputerName, etc), and a
    >number of others use the return value to return a handle or a length of

    a
    >string (eg, GetPrivateProfileString).
    >
    >You could, of course, have two subroutines, one for '0 = success' and one
    >for '0 = error'...but that gets into problems of it's own. This is why

    I
    >tend to encapsulate my API calls.
    >--
    >Colin McGuigan



  14. #14
    Anthony Jones Guest

    Re: Turning API Errors into Basic Errors

    Jim,

    Sorry this is a bit belated but I also use ApiRaise and ApiError. Which I
    supplement with the following

    <Code>
    ' Use with API routines that return a Win32 error value
    Public Sub ApiRaiseIf(ByVal vlError As Long)
    If vlError <> 0 Then ApiRaise vlError
    End Sub

    ' Use with API routines that set lastdllerror and return zero to indicate
    ' failure
    Public Function ApiRaiseIfNull(ByVal ApiRetVal As Long) As Long

    If ApiRetVal = 0 Then
    ApiRaise Err.LastDllError
    Else
    ApiRaiseIfNull = ApiRetVal
    End If

    End Function

    </Code>

    Also in place of vbObjectError + 29000 I use HRESULT_WIN32 (&H80070000).

    --
    Anthony Jones
    Secta Group Ltd
    AnthonyWJones@msn.com



  15. #15
    Anthony Jones Guest

    Re: Turning API Errors into Basic Errors

    Jim,

    Sorry this is a bit belated but I also use ApiRaise and ApiError. Which I
    supplement with the following

    <Code>
    ' Use with API routines that return a Win32 error value
    Public Sub ApiRaiseIf(ByVal vlError As Long)
    If vlError <> 0 Then ApiRaise vlError
    End Sub

    ' Use with API routines that set lastdllerror and return zero to indicate
    ' failure
    Public Function ApiRaiseIfNull(ByVal ApiRetVal As Long) As Long

    If ApiRetVal = 0 Then
    ApiRaise Err.LastDllError
    Else
    ApiRaiseIfNull = ApiRetVal
    End If

    End Function

    </Code>

    Also in place of vbObjectError + 29000 I use HRESULT_WIN32 (&H80070000).

    --
    Anthony Jones
    Secta Group Ltd
    AnthonyWJones@msn.com



Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center
 
 
FAQ
Latest Articles
Java
.NET
XML
Database
Enterprise
Questions? Contact us.
C++
Web Development
Wireless
Latest Tips
Open Source


   Development Centers

   -- Android Development Center
   -- Cloud Development Project Center
   -- HTML5 Development Center
   -- Windows Mobile Development Center