2009-07-11 Michael Barker <mike@middlesoft.co.uk>
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Dynamic / ExcepInfo.cs
1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation. 
4  *
5  * This source code is subject to terms and conditions of the Microsoft Public License. A 
6  * copy of the license can be found in the License.html file at the root of this distribution. If 
7  * you cannot locate the  Microsoft Public License, please send an email to 
8  * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
9  * by the terms of the Microsoft Public License.
10  *
11  * You must not remove this notice, or any other, from this software.
12  *
13  *
14  * ***************************************************************************/
15 using System; using Microsoft;
16
17
18 #if !SILVERLIGHT // ComObject
19
20 using System.Diagnostics;
21 using System.Reflection;
22 using System.Runtime.InteropServices;
23 using System.Security;
24 using ComTypes = System.Runtime.InteropServices.ComTypes;
25
26 #if CODEPLEX_40
27 namespace System.Dynamic {
28 #else
29 namespace Microsoft.Scripting {
30 #endif
31     /// <summary>
32     /// This is similar to ComTypes.EXCEPINFO, but lets us do our own custom marshaling
33     /// </summary>
34     [StructLayout(LayoutKind.Sequential)]
35     internal struct ExcepInfo {
36         private short wCode;
37         private short wReserved;
38         private IntPtr bstrSource;
39         private IntPtr bstrDescription;
40         private IntPtr bstrHelpFile;
41         private int dwHelpContext;
42         private IntPtr pvReserved;
43         private IntPtr pfnDeferredFillIn;
44         private int scode;
45
46 #if DEBUG
47         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2207:InitializeValueTypeStaticFieldsInline")]
48         static ExcepInfo() {
49             Debug.Assert(Marshal.SizeOf(typeof(ExcepInfo)) == Marshal.SizeOf(typeof(ComTypes.EXCEPINFO)));
50         }
51 #endif
52
53         [SecurityCritical]
54         private static string ConvertAndFreeBstr(ref IntPtr bstr) {
55             if (bstr == IntPtr.Zero) {
56                 return null;
57             }
58
59             string result = Marshal.PtrToStringBSTR(bstr);
60             Marshal.FreeBSTR(bstr);
61             bstr = IntPtr.Zero;
62             return result;
63         }
64
65         internal void Dummy() {
66             wCode = 0;
67             wReserved = 0; wReserved++;
68             bstrSource = IntPtr.Zero;
69             bstrDescription = IntPtr.Zero;
70             bstrHelpFile = IntPtr.Zero;
71             dwHelpContext = 0;
72             pfnDeferredFillIn = IntPtr.Zero;
73             pvReserved = IntPtr.Zero;
74             scode = 0;
75
76             throw Error.MethodShouldNotBeCalled();
77         }
78
79         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes")]
80         [SecurityCritical]
81         internal Exception GetException() {
82             Debug.Assert(pfnDeferredFillIn == IntPtr.Zero);
83 #if DEBUG
84             System.Diagnostics.Debug.Assert(wReserved != -1);
85             wReserved = -1; // to ensure that the method gets called only once
86 #endif
87
88             int errorCode = (scode != 0) ? scode : wCode;
89             Exception exception = Marshal.GetExceptionForHR(errorCode);
90
91             string message = ConvertAndFreeBstr(ref bstrDescription);
92             if (message != null) {
93                 // If we have a custom message, create a new Exception object with the message set correctly.
94                 // We need to create a new object because "exception.Message" is a read-only property.
95                 if (exception is COMException) {
96                     exception = new COMException(message, errorCode);
97                 } else {
98                     Type exceptionType = exception.GetType();
99                     ConstructorInfo ctor = exceptionType.GetConstructor(new Type[] { typeof(string) });
100                     if (ctor != null) {
101                         exception = (Exception)ctor.Invoke(new object[] { message });
102                     }
103                 }
104             }
105
106             exception.Source = ConvertAndFreeBstr(ref bstrSource);
107
108             string helpLink = ConvertAndFreeBstr(ref bstrHelpFile);
109             if (helpLink != null && dwHelpContext != 0) {
110                 helpLink += "#" + dwHelpContext;
111             }
112             exception.HelpLink = helpLink;
113
114             return exception;
115         }
116     }
117 }
118
119 #endif