CFRelease call manually ! SOS!

NinineaNininea NinoUSUniversity ✭✭✭

Hey,

I have problem getting finder comment value on file .... Sometimes application user cashed comment... (shows old one) . Here is my code :

            var fileURL = NSUrl.FromFilename (imgPath);
            var mMDItemRef = MDItemCreateWithURL (IntPtr.Zero, fileURL.Handle);
            var mCFTypeRef = MDItemCopyAttribute (mMDItemRef, new CFString ("kMDItemFinderComment").Handle);
            var finderComment = NSString.FromHandle (mCFTypeRef);
            fileURL = null;

            return finderComment;

While searching I found the example:

StringRef comment = MDItemCopyAttribute(item,kMDItemFinderComment);
if (comment)
{
[metadata setObject:(NSString*)comment forKey:@comment];
CFRelease(comment);
}

what I messing is to call CFRelease ... but have no idea how to use it in xamarin....

Any help?

Posts

  • TimothyRisiTimothyRisi Timothy Risi USForum Administrator, Xamarin Team Xamurai

    Hi Nininea,

    Looking at your code snippet there compared to the objective-c sample, it looks like the equivalent for the "comment" field in the objective-c sample would be your

    new CFString ("kMDItemFinderComment").
    

    They release the comment field after using it. To do the same in C#, you'd have to create the CFString before calling MDItemCopyAttribute as a field and pass that into the method instead, then call the Dispose method on it after using it. Something like:

    var fileURL = NSUrl.FromFilename (imgPath);
    var mMDItemRef = MDItemCreateWithURL (IntPtr.Zero, fileURL.Handle);
    CFString comment = new CFString ("kMDItemFinderComment")
    var mCFTypeRef = MDItemCopyAttribute (mMDItemRef, comment.Handle);
    var finderComment = NSString.FromHandle (mCFTypeRef);
    comment.Dispose ();
    fileURL = null;
    
    return finderComment;
    
  • DaveHuntDaveHunt David Hunt USMember ✭✭✭✭✭

    @TimothyRisi - Actually, the equivalent to "comment" would be "mCFTypeRef". However, I don't know how you would release that since I don't know how that variable is being marshaled. In Obj-C it would probably be a CFStringRef, but the interop being used defines it simply as IntPtr.

  • TimothyRisiTimothyRisi Timothy Risi USForum Administrator, Xamarin Team Xamurai

    @DaveHunt said:
    @TimothyRisi - Actually, the equivalent to "comment" would be "mCFTypeRef". However, I don't know how you would release that since I don't know how that variable is being marshaled. In Obj-C it would probably be a CFStringRef, but the interop being used defines it simply as IntPtr.

    StringRef comment = MDItemCopyAttribute(item,kMDItemFinderComment);
    
    var mCFTypeRef = MDItemCopyAttribute (mMDItemRef, new CFString ("kMDItemFinderComment").Handle);
    

    The way I'm reading it, 'mMDItemRef' would map to item and 'new CFString ("kMDItemFinderComment").Handle)' would map to 'kMDItemFinderComment' (And kMDItemFinderComment is a CFString).

    If it IS mCFTypeRef that needs to be released, it should have a Dispose method the same as CFString.

  • DaveHuntDaveHunt David Hunt USMember ✭✭✭✭✭

    @TimothyRisi - I was going by the sample she linked. In the sample, they're releasing the return value of MDItemCopyAttribute:

    CFStringRef comment = MDItemCopyAttribute(item,kMDItemFinderComment);
    ...
    if (comment)
    {
        [metadata setObject:(NSString*)comment forKey:@"comment"]; 
        CFRelease(comment);
    }
    

    Note that the C# code she's using has MDItemCopyAttribute defined as an interop that returns IntPtr. That's why I'm unsure how to release it. Does the marshaling code know that the IntPtr is actually a CFStringRef or does it just return a bare IntPtr?

  • TimothyRisiTimothyRisi Timothy Risi USForum Administrator, Xamarin Team Xamurai

    Woops, gotcha. Yah I wasn't reading it quite close enough. So in order to release it, you'd probably need to also define an Interop for CFRelease to release the IntPtr.

    [DllImport (Constants.CoreFoundationLibrary, CharSet=CharSet.Unicode)]
    extern static IntPtr CFRelease (IntPtr obj);
    
    var fileURL = NSUrl.FromFilename (imgPath);
    var mMDItemRef = MDItemCreateWithURL (IntPtr.Zero, fileURL.Handle);
    var mCFTypeRef = MDItemCopyAttribute (mMDItemRef, comment.Handle);
    var finderComment = NSString.FromHandle (mCFTypeRef);
    CFRelease (mCFTypeRef);
    fileURL = null;
    
  • NinineaNininea Nino USUniversity ✭✭✭

    Thanks for answers .

    I tried to use this version, but application crashes, but try {} catch{} cant handles this :( so I can't see what is the exception

  • TimothyRisiTimothyRisi Timothy Risi USForum Administrator, Xamarin Team Xamurai

    Is there any crash info in the application output (such as a SIGSEGV error or something)? Do you have a simple repro case you can share that shows the crash happening?

  • NinineaNininea Nino USUniversity ✭✭✭
    edited February 16

    Unfortunately no .
    I set comment from my application:

    public static void SetImageComment (string filePath, string comment)
                {
                    NSMutableString script = new NSMutableString ();
                    script.Append (new NSString ("TELL APPLICATION \"FINDER\"\n" +
                                      $"SET filePath TO \"{filePath}\" AS POSIX FILE \n" +
                                      $"SET COMMENT OF (filePath AS ALIAS) TO \"{comment}\" \n" +
                                                "END TELL"));
                    System.Diagnostics.Debug.WriteLine ("");
                    System.Diagnostics.Debug.WriteLine (script);
                    System.Diagnostics.Debug.WriteLine ("");
    
                    NSDictionary dictionary;
                    NSAppleScript commentScript = new NSAppleScript (script);
                    commentScript.ExecuteAndReturnError (out dictionary);
                    System.Diagnostics.Debug.WriteLine (dictionary?.ToString ());
    
                    var newcomm = GetImageComment (filePath);
    
                    System.Diagnostics.Debug.WriteLine ("image: " + filePath);
                    System.Diagnostics.Debug.WriteLine ("new comment: " + newcomm);
                }
    

    if you will call this code at least for two files (in for cycle ), Then then get comment for the second one, with this code I posed in the question, comment won't be up to date.... but if you check if in finder , new comment is inserted ....

  • DaveHuntDaveHunt David Hunt USMember ✭✭✭✭✭

    It's possible that this is a timing issue between setting the comment and Spotlight indexing the information. What happens if you set the comment, wait some period of time, and then get the comment?

  • NinineaNininea Nino USUniversity ✭✭✭

    unfortunately, I had tried it, got no result... delay doesn't makes sense.

    Also I added one check.. after inserting comment, I call get comment function and log result. comment it up to date, when I trying to get new comment after 4-5 seconds later, it shows the old one .. I'm very confused.

  • DaveHuntDaveHunt David Hunt USMember ✭✭✭✭✭

    @Niniea

    I would suggest you put together a small project that reproduces the problem as @TimothyRisi suggested and posting a link to that. With all of the suggestions we've made for things to try and the small snippets of code you've posted, it's hard to get a clear picture of exactly how your code is structured and what it's doing.

  • NinineaNininea Nino USUniversity ✭✭✭
    edited February 22

    @TimothyRisi

    Termination Signal:    Trace/BPT trap: 5
    Termination Reason:    Namespace SIGNAL, Code 0x5
    Terminating Process:   exc handler [0]
    
    Application Specific Information:
    *** CFRelease() called with NULL ***
    

    this is what report window says. does it make sense ?

  • NinineaNininea Nino USUniversity ✭✭✭

    Here is demo application, i added read me file and here is written how you reproduce the bug.

    Demo Application

    @TimothyRisi @DaveHunt

  • DaveHuntDaveHunt David Hunt USMember ✭✭✭✭✭

    @Nininea said:
    @TimothyRisi

    Termination Signal:    Trace/BPT trap: 5
    Termination Reason:    Namespace SIGNAL, Code 0x5
    Terminating Process:   exc handler [0]
    
    Application Specific Information:
    *** CFRelease() called with NULL ***
    

    this is what report window says. does it make sense ?

    This is significant:

    *** CFRelease() called with NULL ***

    That means the handle you're releasing is null, which most likely means that MDItemCopyAttribute returned null. This can happen when there is an error reading the attribute or when the attribute doesn't exist for the specified item.

    You need to check the return value and make sure it's not null before processing further.

  • NinineaNininea Nino USUniversity ✭✭✭

    hm, not sure how to handle this , because when I call CFRelease manually mCFTypeRef is not null ....

    How does CFRelease work in xamarin?

  • DaveHuntDaveHunt David Hunt USMember ✭✭✭✭✭

    Is there a stack trace that goes along with that report window?

  • NinineaNininea Nino USUniversity ✭✭✭

    this is system crash report, not hummable exception :D I attached the file

    bb.zip 26.5K
  • DaveHuntDaveHunt David Hunt USMember ✭✭✭✭✭

    The crash report is pretty clear that CFRelease is being passed a NULL.

    Have you run the code with breakpoints in the GetImageComment method and checked every return value?

Sign In or Register to comment.