Beispiel #1
0
        private static NSObject DoCreateNativeException(Exception e)
        {
            NSObject native;

            IntPtr   nameBuffer   = Marshal.StringToHGlobalAuto(e.GetType().ToString());
            IntPtr   reasonBuffer = Marshal.StringToHGlobalAuto(e.Message);
            IntPtr   keyBuffer    = Marshal.StringToHGlobalAuto(".NET exception");
            GCHandle handle       = new GCHandle();

            try
            {
                // Create the name, reason, and userInfo objects.
                NSObject name     = (NSObject) new Class("NSString").Call("alloc").Call("initWithUTF8String:", nameBuffer);
                NSObject reason   = (NSObject) new Class("NSString").Call("alloc").Call("initWithUTF8String:", reasonBuffer);
                NSObject userInfo = (NSObject) new Class("NSMutableDictionary").Call("alloc").Call("init");
                name.autorelease();
                reason.autorelease();
                userInfo.autorelease();

                // Add the original System.Exception to userInfo.
                NSObject key = (NSObject) new Class("NSString").Call("alloc").Call("initWithUTF8String:", keyBuffer);
                key.autorelease();

                try
                {
                    using (MemoryStream stream = new MemoryStream())
                    {
                        BinaryFormatter formatter = new BinaryFormatter();
                        formatter.Serialize(stream, e);

                        byte[] data = stream.ToArray();
                        handle = GCHandle.Alloc(data, GCHandleType.Pinned);
                        NSObject buffer = (NSObject) new Class("NSData").Call("dataWithBytes:length:", handle.AddrOfPinnedObject(), (uint)stream.Length);
                        Unused.Value = userInfo.Call("setObject:forKey:", buffer, key);
                    }
                }
                catch (Exception ee)
                {
                    // Typically this will happen if e is not serializable.
                    Console.Error.WriteLine("{0}", ee);
                    Console.Error.Flush();
                }

                // Create the NSException.
                native = (NSObject) new Class("NSException").Call("exceptionWithName:reason:userInfo:", name, reason, userInfo);
            }
            finally
            {
                Marshal.FreeHGlobal(nameBuffer);
                Marshal.FreeHGlobal(reasonBuffer);
                Marshal.FreeHGlobal(keyBuffer);

                if (handle.IsAllocated)
                {
                    handle.Free();
                }
            }

            return(native);
        }
Beispiel #2
0
        /// <summary>Converts an <c>NSException</c> into a managed exception and throws it.</summary>
        /// <param name = "instance">The <a href ="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/nsexception_Class/Reference/Reference.html">NSException</a>
        /// pointer.</param>
        /// <remarks>If the <c>NSException</c> wraps a managed exception then
        /// <c>TargetInvocationException</c> is thrown instead with the inner exception
        /// set to the original exception.</remarks>
        public static void Raise(IntPtr instance)
        {
            NSObject obj = new NSObject(instance);

            if (obj.isMemberOfClass(new Class("NSException")))
            {
                // See if the userInfo contains a .NET exception.
                NSObject userInfo = (NSObject)obj.Call("userInfo");

                if (userInfo != null && (IntPtr)userInfo != IntPtr.Zero)
                {
                    IntPtr   keyBuffer = Marshal.StringToHGlobalAuto(".NET exception");
                    NSObject key       = (NSObject) new Class("NSString").Call("alloc").Call("initWithUTF8String:", keyBuffer);
                    key.autorelease();
                    Marshal.FreeHGlobal(keyBuffer);

                    NSObject data = (NSObject)userInfo.Call("objectForKey:", key);
                    if (data != null && !data.IsNil())
                    {
                        // If it does then get the serialized exception bytes,
                        IntPtr ptr   = (IntPtr)data.Call("bytes");
                        uint   bytes = (uint)data.Call("length");

                        // copy them into a managed buffer,
                        byte[] buffer = new byte[bytes];
                        Marshal.Copy(ptr, buffer, 0, (int)bytes);

                        // and raise the original exception.
                        using (MemoryStream stream = new MemoryStream(buffer))
                        {
                            BinaryFormatter formatter = new BinaryFormatter();
                            Exception       e         = (Exception)formatter.Deserialize(stream);

                            throw new TargetInvocationException("Exception has been thrown by the (managed) target of an Objective-C method call.", e);                                 // yes TargetInvocationException sucks, but it preserves the original stack crawl...
                        }
                    }
                }
            }

            throw new CocoaException(obj);
        }