Search code examples
c#cocoamonomac

MonoMac NSWorkspace.RecycleUrls vs. recycleURLs:completionHandler


According to the MonoMac documentation the signature for NSWorkspace.RecycleUrls is:

[MonoMac.Foundation.Export("recycleURLs:completionHandler:")]
public virtual void RecycleUrls (MonoMac.Foundation.NSDictionary urls, NSWorkspaceUrlHandler completionHandler)

According to Apple's documentation for NSWorkspace the signature for recycleURLs:completionHandler is:

- (void)recycleURLs:(NSArray *)URLs completionHandler:(void (^)(NSDictionary *newURLs, NSError *error))handler

I have an array of URLs that I want recycled.

Here I'm stumped - the Apple documentation says the first parameter is an NSArray but MonoMac wants an NSDictionary. All the functions to construct an NSDictionary want keys and values (unsurprisingly) whereas I only have values.

Is there anything to be done other than taking MonoMac's implementation of RecycleUrls (reproduced below) and rewriting it to use an NSArray?

[Export("recycleURLs:completionHandler:")]
public unsafe virtual void RecycleUrls(NSDictionary urls, NSWorkspaceUrlHandler completionHandler)
{
    if (urls == null)
    {
        throw new ArgumentNullException("urls");
    }
    if (completionHandler == null)
    {
        throw new ArgumentNullException("completionHandler");
    }
    BlockLiteral blockLiteral = default(BlockLiteral);
    blockLiteral.SetupBlock(NSWorkspace.static_InnerNSWorkspaceUrlHandler, completionHandler);
    if (this.IsDirectBinding)
    {
        Messaging.void_objc_msgSend_IntPtr_IntPtr(base.Handle, NSWorkspace.selRecycleURLsCompletionHandler_, urls.Handle, (IntPtr)((void*)(&blockLiteral)));
    }
    else
    {
        Messaging.void_objc_msgSendSuper_IntPtr_IntPtr(base.SuperHandle, NSWorkspace.selRecycleURLsCompletionHandler_, urls.Handle, (IntPtr)((void*)(&blockLiteral)));
    }
    blockLiteral.CleanupBlock();
}

Solution

  • Mono's binding was incorrect, I changed both NSWorkspace.RecycleUrls() and NSWorkspace.DuplicateUrls() to take an NSArray instead of NSDictionary, monomac commit b1eda57.

    This is the generated code:

        [Export ("recycleURLs:completionHandler:")]
        public unsafe virtual void RecycleUrls (NSArray urls, NSWorkspaceUrlHandler completionHandler)
        {
            if (urls == null)
                throw new ArgumentNullException ("urls");
            if (completionHandler == null)
                throw new ArgumentNullException ("completionHandler");
            BlockLiteral *block_ptr_completionHandler;
            BlockLiteral block_completionHandler;
            block_completionHandler = new BlockLiteral ();
            block_ptr_completionHandler = &block_completionHandler;
            block_completionHandler.SetupBlock (static_InnerNSWorkspaceUrlHandler, completionHandler);
    
            if (IsDirectBinding) {
                MonoMac.ObjCRuntime.Messaging.void_objc_msgSend_IntPtr_IntPtr (this.Handle, selRecycleURLsCompletionHandler_, urls.Handle, (IntPtr) block_ptr_completionHandler);
            } else {
                MonoMac.ObjCRuntime.Messaging.void_objc_msgSendSuper_IntPtr_IntPtr (this.SuperHandle, selRecycleURLsCompletionHandler_, urls.Handle, (IntPtr) block_ptr_completionHandler);
            }
            block_ptr_completionHandler->CleanupBlock ();
    
        }
    
        [Export ("duplicateURLs:completionHandler:")]
        public unsafe virtual void DuplicateUrls (NSArray urls, NSWorkspaceUrlHandler completionHandler)
        {
            if (urls == null)
                throw new ArgumentNullException ("urls");
            if (completionHandler == null)
                throw new ArgumentNullException ("completionHandler");
            BlockLiteral *block_ptr_completionHandler;
            BlockLiteral block_completionHandler;
            block_completionHandler = new BlockLiteral ();
            block_ptr_completionHandler = &block_completionHandler;
            block_completionHandler.SetupBlock (static_InnerNSWorkspaceUrlHandler, completionHandler);
    
            if (IsDirectBinding) {
                MonoMac.ObjCRuntime.Messaging.void_objc_msgSend_IntPtr_IntPtr (this.Handle, selDuplicateURLsCompletionHandler_, urls.Handle, (IntPtr) block_ptr_completionHandler);
            } else {
                MonoMac.ObjCRuntime.Messaging.void_objc_msgSendSuper_IntPtr_IntPtr (this.SuperHandle, selDuplicateURLsCompletionHandler_, urls.Handle, (IntPtr) block_ptr_completionHandler);
            }
            block_ptr_completionHandler->CleanupBlock ();
    
        }
    

    Quick test:

        void TestUrls ()
        {
            var path = Path.GetTempFileName ();
            Console.WriteLine ("TEST: {0} {1}", path, File.Exists (path));
    
            var array = new NSMutableArray ();
            var url = new NSUrl ("file://" + path);
            array.Add (url);
    
            var workspace = NSWorkspace.SharedWorkspace;
            workspace.DuplicateUrls (array, (urls, error) => {
                Console.WriteLine ("DUPLICATED: {0} {1}", urls, error);
                array.Add (urls.Values [0]);
    
                workspace.RecycleUrls (array, (urls2, error2) => {
                    Console.WriteLine ("RECYCLED: {0} {1} {2}",
                                       urls2, error2, File.Exists (path));
                });
            });
        }