{"id":1815,"date":"2005-03-31T08:13:53","date_gmt":"2005-03-31T07:13:53","guid":{"rendered":"https:\/\/yvespeneveyre8e29bf869d.wordpress.com\/2005\/03\/31\/composant-com-en-net-et-hresult-net-com-component-and-hresult\/"},"modified":"2005-03-31T08:13:53","modified_gmt":"2005-03-31T07:13:53","slug":"composant-com-en-net-et-hresult-net-com-component-and-hresult","status":"publish","type":"post","link":"https:\/\/www.peneveyre.com\/en\/2005\/03\/31\/composant-com-en-net-et-hresult-net-com-component-and-hresult\/","title":{"rendered":"Composant COM en .NET et HRESULT. .NET COM component and HRESULT"},"content":{"rendered":"<p><P>Travaillant actuellement pour un client d??sirant utiliser un composant .NET depuis Office 2000, il a donc fallu s&#8217;attaquer ?? COM Interop. Et, bien que la documentation le dise, il est possible d&#8217;avoir quelques surprises lorsqu&#8217;il s&#8217;agit de g??rer les exceptions et les erreurs COM.<\/P><br \/>\n<P>Prenons donc le code suivant :<\/P><br \/>\n<P><SPAN>[ComVisible(<SPAN>true<\/SPAN>)]<BR><SPAN>public<\/SPAN> <SPAN>int<\/SPAN> myMethod()<BR>{<BR><SPAN>&nbsp; \/\/ snip<\/SPAN><BR><SPAN>&nbsp; throw<\/SPAN> <SPAN>new<\/SPAN> myException(<SPAN>&#8220;Description&#8221;<\/SPAN>, 2500);<BR><SPAN>&nbsp; \/\/ snip<\/SPAN><BR><SPAN>&nbsp; \/\/ Do something here<\/SPAN><BR><SPAN>&nbsp; return<\/SPAN> 0;<BR>}<\/SPAN><\/P><SPAN><br \/>\n<P><SPAN><SPAN>public<\/SPAN> <SPAN>class<\/SPAN> myException : ApplicationException<BR>{<BR><SPAN>&nbsp; \/\/ COM Error base number is 0x80040000<\/SPAN><BR><SPAN>&nbsp; private<\/SPAN> <SPAN>const<\/SPAN> <SPAN>int<\/SPAN> kCOMErrorBaseNumber <SPAN>=<\/SPAN> <SPAN>unchecked<\/SPAN>((<SPAN>int<\/SPAN>) 0x80040000);<BR><SPAN>&nbsp; public<\/SPAN> myException() : <SPAN>base<\/SPAN>(){}<BR><SPAN>&nbsp; public<\/SPAN> myException(<SPAN>string<\/SPAN> strMessage, <SPAN>int<\/SPAN> ErrorCode) : <SPAN>base<\/SPAN>(strMessage)<BR>&nbsp; {<BR><SPAN>&nbsp;&nbsp;&nbsp; \/\/ HResult = kCOMErrorBaseNumber + ErrorCode);<\/SPAN><BR>&nbsp;&nbsp;&nbsp; HResult <SPAN>=<\/SPAN> ErrorCode);<BR>&nbsp; }<BR>}<\/SPAN><\/P><br \/>\n<P><SPAN><FONT face=\"Verdana\" size=\"2\">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 :<\/FONT><\/SPAN><\/P><SPAN><br \/>\n<P><SPAN><SPAN>Sub<\/SPAN> Test()<BR><SPAN>&nbsp; On<\/SPAN> <SPAN>Error<\/SPAN> <SPAN>GoTo<\/SPAN> err_handling<BR><SPAN>&nbsp; Dim<\/SPAN> a <SPAN>As<\/SPAN> <SPAN>New<\/SPAN> myDotNetComponent<BR><SPAN>&nbsp; Dim<\/SPAN> b <SPAN>As<\/SPAN> <SPAN>Long<\/SPAN><BR>&nbsp; b <SPAN>=<\/SPAN> a.myMethod()<BR><SPAN>&nbsp; &#8216; Do something<\/SPAN><BR><SPAN>&nbsp; Exit<\/SPAN> <SPAN>Sub<\/SPAN><BR><BR>err_handling:<BR><SPAN>&nbsp; MsgBox<\/SPAN> <SPAN>Err<\/SPAN>.<SPAN>Number<\/SPAN><BR><SPAN>End<\/SPAN> <SPAN>Sub<\/SPAN><\/SPAN><\/P><\/SPAN><br \/>\n<P><SPAN><FONT face=\"Verdana\" size=\"2\">Le seul moyen de fixer le num??ro d&#8217;erreur&nbsp;qui sera retourn?? au client COM est de le faire dans le constructeur de l&#8217;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&#8217;??tiquette err_handling n&#8217;est pas ex??cut??. Surprise, non ?<\/FONT><\/SPAN><\/P><br \/>\n<P><SPAN><FONT face=\"Verdana\" size=\"2\">L&#8217;explication se trouve dans la <A href=\"http:\/\/msdn.microsoft.com\/library\/default.asp?url=\/library\/en-us\/com\/htm\/error_5g6r.asp\">documentation Microsoft<\/A>. On peut y lire qu&#8217;un code d&#8217;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&#8217;elle est propag??e au-del?? vers le code client, si le code HRESULT affect?? n&#8217;est pas correct, on risque de passer ?? c??t?? d&#8217;un tel probl??me. Il est possible de corriger cela en ajoutant la valeur 0x80000000 ?? notre code d&#8217;erreur pour que cela fonctionne. Pour ??tre plus s??r de ne pas entrer en collision avec des code existants, j&#8217;ai ajout?? la valeur 0x80040000.<\/FONT><\/SPAN><\/P><br \/>\n<P><SPAN><FONT face=\"Verdana\" size=\"2\"><\/FONT><\/SPAN>&nbsp;<\/P><SPAN><br \/>\n<P><FONT face=\"Verdana\" size=\"2\"><EM>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.<\/EM><\/FONT><\/P><br \/>\n<P><FONT face=\"Verdana\" size=\"2\"><EM>So, take the following code :<\/EM><\/FONT><\/P><br \/>\n<P><SPAN>[ComVisible(<SPAN>true<\/SPAN>)]<BR><SPAN>public<\/SPAN> <SPAN>int<\/SPAN> myMethod()<BR>{<BR><SPAN>&nbsp; \/\/ snip<\/SPAN><BR><SPAN>&nbsp; throw<\/SPAN> <SPAN>new<\/SPAN> myException(<SPAN>&#8220;Description&#8221;<\/SPAN>, 2500);<BR><SPAN>&nbsp; \/\/ snip<\/SPAN><BR><SPAN>&nbsp; \/\/ Do something here<\/SPAN><BR><SPAN>&nbsp; return<\/SPAN> 0;<BR>}<\/SPAN><\/P><SPAN><br \/>\n<P><SPAN><SPAN>public<\/SPAN> <SPAN>class<\/SPAN> myException : ApplicationException<BR>{<BR><SPAN>&nbsp; \/\/ COM Error base number is 0x80040000<\/SPAN><BR><SPAN>&nbsp; private<\/SPAN> <SPAN>const<\/SPAN> <SPAN>int<\/SPAN> kCOMErrorBaseNumber <SPAN>=<\/SPAN> <SPAN>unchecked<\/SPAN>((<SPAN>int<\/SPAN>) 0x80040000);<BR><SPAN>&nbsp; public<\/SPAN> myException() : <SPAN>base<\/SPAN>(){}<BR><SPAN>&nbsp; public<\/SPAN> myException(<SPAN>string<\/SPAN> strMessage, <SPAN>int<\/SPAN> ErrorCode) : <SPAN>base<\/SPAN>(strMessage)<BR>&nbsp; {<BR><SPAN>&nbsp;&nbsp;&nbsp; \/\/ HResult = kCOMErrorBaseNumber + ErrorCode);<\/SPAN><BR>&nbsp;&nbsp;&nbsp; HResult <SPAN>=<\/SPAN> ErrorCode);<BR>&nbsp; }<BR>}<\/SPAN><\/P><br \/>\n<P><SPAN><FONT face=\"Verdana\" size=\"2\"><EM>On the client side, for exemple from Excel, adding the right reference to our .NET written COM component, write the following code :<\/EM><\/FONT><\/SPAN><\/P><SPAN><br \/>\n<P><SPAN><SPAN>Sub<\/SPAN> Test()<BR><SPAN>&nbsp; On<\/SPAN> <SPAN>Error<\/SPAN> <SPAN>GoTo<\/SPAN> err_handling<BR><SPAN>&nbsp; Dim<\/SPAN> a <SPAN>As<\/SPAN> <SPAN>New<\/SPAN> myDotNetComponent<BR><SPAN>&nbsp; Dim<\/SPAN> b <SPAN>As<\/SPAN> <SPAN>Long<\/SPAN><BR>&nbsp; b <SPAN>=<\/SPAN> a.myMethod()<BR><SPAN>&nbsp; &#8216; Do something<\/SPAN><BR><SPAN>&nbsp; Exit<\/SPAN> <SPAN>Sub<\/SPAN><BR><BR>err_handling:<BR><SPAN>&nbsp; MsgBox<\/SPAN> <SPAN>Err<\/SPAN>.<SPAN>Number<\/SPAN><BR><SPAN>End<\/SPAN> <SPAN>Sub<\/SPAN><\/SPAN><\/P><\/SPAN><br \/>\n<P><SPAN><FONT face=\"Verdana\" size=\"2\"><EM>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&#8217;t it ?<\/EM><\/FONT><\/SPAN><\/P><br \/>\n<P><SPAN><FONT face=\"Verdana\" size=\"2\"><EM>The explanation can be found in the <\/EM><A href=\"http:\/\/msdn.microsoft.com\/library\/default.asp?url=\/library\/en-us\/com\/htm\/error_5g6r.asp\"><EM>Microsoft documentation<\/EM><\/A><EM>. 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&nbsp;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.<\/EM><\/FONT><\/SPAN><\/SPAN><\/P><\/SPAN><\/SPAN><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Le code HRESULT affect?? dans le constructeur d&#8217;une exception n&#8217;est pas anodin. Pour qu&#8217;une erreur soit d??tect??e du c??t?? client, il faut que cette valeur soit sup??rieur ?? 0x80000000. The HRESULT code set in an exception constructor is very important. In order to detect the error on the client side, that value must be greater than 0x80000000.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"","_et_pb_old_content":"","_et_gb_content_width":"","footnotes":""},"categories":[1],"tags":[],"class_list":["post-1815","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.peneveyre.com\/en\/wp-json\/wp\/v2\/posts\/1815","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.peneveyre.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.peneveyre.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.peneveyre.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.peneveyre.com\/en\/wp-json\/wp\/v2\/comments?post=1815"}],"version-history":[{"count":0,"href":"https:\/\/www.peneveyre.com\/en\/wp-json\/wp\/v2\/posts\/1815\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.peneveyre.com\/en\/wp-json\/wp\/v2\/media?parent=1815"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.peneveyre.com\/en\/wp-json\/wp\/v2\/categories?post=1815"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.peneveyre.com\/en\/wp-json\/wp\/v2\/tags?post=1815"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}