Composant COM en .NET et HRESULT. .NET COM component and HRESULT

Written by Yves

March 31, 2005

Travaillant actuellement pour un client d??sirant utiliser un composant .NET depuis Office 2000, il a donc fallu s’attaquer ?? COM Interop. Et, bien que la documentation le dise, il est possible d’avoir quelques surprises lorsqu’il s’agit de g??rer les exceptions et les erreurs COM.


Prenons donc le code suivant :


[ComVisible(true)]
public int myMethod()
{
  // snip
  throw new myException(“Description”, 2500);
  // snip
  // Do something here
  return 0;
}


public class myException : ApplicationException
{
  // COM Error base number is 0x80040000
  private const int kCOMErrorBaseNumber = unchecked((int) 0x80040000);
  public myException() : base(){}
  public myException(string strMessage, int ErrorCode) : base(strMessage)
  {
    // HResult = kCOMErrorBaseNumber + ErrorCode);
    HResult = ErrorCode);
  }
}


Du c??t?? client, par exemple sous Excel, en ajoutant la bonne r??f??rence sur notre composant COM ??crit en .NET, ??crivons le code suivant :


Sub Test()
  On Error GoTo err_handling
  Dim a As New myDotNetComponent
  Dim b As Long
  b = a.myMethod()
  ‘ Do something
  Exit Sub

err_handling:
  MsgBox Err.Number
End Sub


Le seul moyen de fixer le num??ro d’erreur qui sera retourn?? au client COM est de le faire dans le constructeur de l’exception, comme on peut le voir dans le code du composant COM. Si on ex??cute le code VB, aucune erreur ne sera retourn??e. Le code situ?? sous l’??tiquette err_handling n’est pas ex??cut??. Surprise, non ?


L’explication se trouve dans la documentation Microsoft. On peut y lire qu’un code d’erreur HRESULT doit avoir son bit de poids fort mis ?? 1 pour que ce soit consid??r?? pour une erreur. Ainsi donc, m??me si une exception est lev??e dans le composant COM .NET et qu’elle est propag??e au-del?? vers le code client, si le code HRESULT affect?? n’est pas correct, on risque de passer ?? c??t?? d’un tel probl??me. Il est possible de corriger cela en ajoutant la valeur 0x80000000 ?? notre code d’erreur pour que cela fonctionne. Pour ??tre plus s??r de ne pas entrer en collision avec des code existants, j’ai ajout?? la valeur 0x80040000.


 


Actually working for a customer which would like to use a .NET component from an Office 2000 application, I had to work with COM Interop. And, even the documentation understandable, it is possible to have some surprises when managing and handling exceptions and COM errors.


So, take the following code :


[ComVisible(true)]
public int myMethod()
{
  // snip
  throw new myException(“Description”, 2500);
  // snip
  // Do something here
  return 0;
}


public class myException : ApplicationException
{
  // COM Error base number is 0x80040000
  private const int kCOMErrorBaseNumber = unchecked((int) 0x80040000);
  public myException() : base(){}
  public myException(string strMessage, int ErrorCode) : base(strMessage)
  {
    // HResult = kCOMErrorBaseNumber + ErrorCode);
    HResult = ErrorCode);
  }
}


On the client side, for exemple from Excel, adding the right reference to our .NET written COM component, write the following code :


Sub Test()
  On Error GoTo err_handling
  Dim a As New myDotNetComponent
  Dim b As Long
  b = a.myMethod()
  ‘ Do something
  Exit Sub

err_handling:
  MsgBox Err.Number
End Sub


The only way to set the error code that will be returned to the COM client is to do that in the exception constructor as we can see it in the COM component code. If we run the VB code, no error will be returned and the err_handling labelled code will not be run. Surprising isn’t it ?


The explanation can be found in the Microsoft documentation. We can read that an HRESULT error code must have its high-order bit must be set to 1 to be considered as en error. So, even en exception is raised in the .NET COM component and bubbled to the client code, if the HRESULT code is not correctly set, we can miss an error. It is possible to change that adding a 0x80000000 value to our error code. But, to be sure that we are not colliding with existing error codes, I added the value 0x80040000.

You May Also Like…

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *