1 /////////////////////////////////////////////////////////////////////////////
2 // Name: mac/mimetype.cpp
3 // Purpose: Mac Carbon implementation for wx mime-related classes
8 // Copyright: (c) 2005 Ryan Norton (<wxprojects@comcast.net>)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13 #pragma implementation "mimetype.h"
16 // for compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
24 #include "wx/string.h"
36 #include "wx/dynarray.h"
37 #include "wx/confbase.h"
39 #include "wx/mac/mimetype.h"
40 #include "wx/mac/private.h" //wxMacMakeStringFromPascal
42 // other standard headers
44 #include <InternetConfig.h> //For mime types
47 /* START CODE SAMPLE FROM TECHNOTE 1002 (http://developer.apple.com/technotes/tn/tn1002.html) */
49 /* IsRemoteVolume can be used to find out if the
50 volume referred to by vRefNum is a remote volume
51 located somewhere on a network. the volume's attribute
52 flags (copied from the GetVolParmsInfoBuffer structure)
53 are returned in the longword pointed to by vMAttrib. */
54 OSErr
IsRemoteVolume(short vRefNum
, Boolean
*isRemote
, long *vMAttrib
) {
56 GetVolParmsInfoBuffer volinfo
;
58 volPB
.ioParam
.ioVRefNum
= vRefNum
;
59 volPB
.ioParam
.ioNamePtr
= NULL
;
60 volPB
.ioParam
.ioBuffer
= (Ptr
) &volinfo
;
61 volPB
.ioParam
.ioReqCount
= sizeof(volinfo
);
62 err
= PBHGetVolParmsSync(&volPB
);
64 *isRemote
= (volinfo
.vMServerAdr
!= 0);
65 *vMAttrib
= volinfo
.vMAttrib
;
71 /* BuildVolumeList fills the array pointed to by vols with
72 a list of the currently mounted volumes. If includeRemote
73 is true, then remote server volumes will be included in
74 the list. When remote server volumes are included in the
75 list, they will be added to the end of the list. On entry,
76 *count should contain the size of the array pointed to by
77 vols. On exit, *count will be set to the number of id numbers
78 placed in the array. If vMAttribMask is non-zero, then
79 only volumes with matching attributes are added to the
80 list of volumes. bits in the vMAttribMask should use the
81 same encoding as bits in the vMAttrib field of
82 the GetVolParmsInfoBuffer structure. */
83 OSErr
BuildVolumeList(Boolean includeRemote
, short *vols
,
84 long *count
, long vMAttribMask
) {
91 /* set up and check parameters */
92 volPB
.volumeParam
.ioNamePtr
= NULL
;
94 if (*count
== 0) return noErr
;
96 /* iterate through volumes */
97 for (volPB
.volumeParam
.ioVolIndex
= 1;
98 PBHGetVInfoSync(&volPB
) == noErr
;
99 volPB
.volumeParam
.ioVolIndex
++) {
101 /* skip remote volumes, if necessary */
102 err
= IsRemoteVolume(volPB
.volumeParam
.ioVRefNum
, &isRemote
, &vMAttrib
);
103 if (err
!= noErr
) goto bail
;
104 if ( ( includeRemote
|| ! isRemote
)
105 && (vMAttrib
& vMAttribMask
) == vMAttribMask
) {
107 /* add local volumes at the front, remote
108 volumes at the end */
110 vols
[nlocal
+ nremote
++] = volPB
.volumeParam
.ioVRefNum
;
113 BlockMoveData(vols
+nlocal
, vols
+nlocal
+1,
114 nremote
*sizeof(short));
115 vols
[nlocal
++] = volPB
.volumeParam
.ioVRefNum
;
119 if ((nlocal
+ nremote
) >= *count
) break;
123 *count
= (nlocal
+ nremote
);
128 /* FindApplication iterates through mounted volumes
129 searching for an application with the given creator
130 type. If includeRemote is true, then remote volumes
131 will be searched (after local ones) for an application
132 with the creator type. */
136 /* Hacked to output to appName */
138 OSErr
FindApplication(OSType appCreator
, Boolean includeRemote
, Str255 appName
, FSSpec
* appSpec
) {
139 short rRefNums
[kMaxVols
];
144 /* get a list of volumes - with desktop files */
146 err
= BuildVolumeList(includeRemote
, rRefNums
, &volCount
,
147 (1<<bHasDesktopMgr
) );
148 if (err
!= noErr
) return err
;
150 /* iterate through the list */
151 for (i
=0; i
<volCount
; i
++) {
153 /* has a desktop file? */
154 desktopPB
.ioCompletion
= NULL
;
155 desktopPB
.ioVRefNum
= rRefNums
[i
];
156 desktopPB
.ioNamePtr
= NULL
;
157 desktopPB
.ioIndex
= 0;
158 err
= PBDTGetPath(&desktopPB
);
159 if (err
!= noErr
) continue;
161 /* has the correct app?? */
162 desktopPB
.ioFileCreator
= appCreator
;
163 desktopPB
.ioNamePtr
= appName
;
164 err
= PBDTGetAPPLSync(&desktopPB
);
165 if (err
!= noErr
) continue;
167 /* make a file spec referring to it */
168 err
= FSMakeFSSpec(rRefNums
[i
],
169 desktopPB
.ioAPPLParID
, appName
,
171 if (err
!= noErr
) continue;
180 /* END CODE SAMPLE FROM TECHNOTE 1002 (http://developer.apple.com/technotes/tn/tn1002.html) */
182 //yeah, duplicated code
183 pascal OSErr
FSpGetFullPath(const FSSpec
*spec
,
184 short *fullPathLength
,
196 /* Default to noErr */
197 realResult
= result
= noErr
;
199 /* work around Nav Services "bug" (it returns invalid FSSpecs with empty names) */
201 if ( spec->name[0] == 0 )
203 result = FSMakeFSSpecCompat(spec->vRefNum, spec->parID, spec->name, &tempSpec);
208 /* Make a copy of the input FSSpec that can be modified */
209 BlockMoveData(spec
, &tempSpec
, sizeof(FSSpec
));
212 if ( result
== noErr
)
214 if ( tempSpec
.parID
== fsRtParID
)
216 /* The object is a volume */
218 /* Add a colon to make it a full pathname */
220 tempSpec
.name
[tempSpec
.name
[0]] = ':';
223 result
= PtrToHand(&tempSpec
.name
[1], fullPath
, tempSpec
.name
[0]);
227 /* The object isn't a volume */
229 /* Is the object a file or a directory? */
230 pb
.dirInfo
.ioNamePtr
= tempSpec
.name
;
231 pb
.dirInfo
.ioVRefNum
= tempSpec
.vRefNum
;
232 pb
.dirInfo
.ioDrDirID
= tempSpec
.parID
;
233 pb
.dirInfo
.ioFDirIndex
= 0;
234 result
= PBGetCatInfoSync(&pb
);
235 /* Allow file/directory name at end of path to not exist. */
237 if ( (result
== noErr
) || (result
== fnfErr
) )
239 /* if the object is a directory, append a colon so full pathname ends with colon */
240 if ( (result
== noErr
) && (pb
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0 )
243 tempSpec
.name
[tempSpec
.name
[0]] = ':';
246 /* Put the object name in first */
247 result
= PtrToHand(&tempSpec
.name
[1], fullPath
, tempSpec
.name
[0]);
248 if ( result
== noErr
)
250 /* Get the ancestor directory names */
251 pb
.dirInfo
.ioNamePtr
= tempSpec
.name
;
252 pb
.dirInfo
.ioVRefNum
= tempSpec
.vRefNum
;
253 pb
.dirInfo
.ioDrParID
= tempSpec
.parID
;
254 do /* loop until we have an error or find the root directory */
256 pb
.dirInfo
.ioFDirIndex
= -1;
257 pb
.dirInfo
.ioDrDirID
= pb
.dirInfo
.ioDrParID
;
258 result
= PBGetCatInfoSync(&pb
);
259 if ( result
== noErr
)
261 /* Append colon to directory name */
263 tempSpec
.name
[tempSpec
.name
[0]] = ':';
265 /* Add directory name to beginning of fullPath */
266 (void) Munger(*fullPath
, 0, NULL
, 0, &tempSpec
.name
[1], tempSpec
.name
[0]);
269 } while ( (result
== noErr
) && (pb
.dirInfo
.ioDrDirID
!= fsRtDirID
) );
275 if ( result
== noErr
)
277 /* Return the length */
278 *fullPathLength
= GetHandleSize(*fullPath
);
279 result
= realResult
; /* return realResult in case it was fnfErr */
283 /* Dispose of the handle and return NULL and zero length */
284 if ( *fullPath
!= NULL
)
286 DisposeHandle(*fullPath
);
296 // On the mac there are two ways to open a file - one is through apple events and the
297 // finder, another is through mime types.
299 // So, really there are two ways to implement wxFileType...
301 // Mime types are only available on OS 8.1+ through the InternetConfig API
303 // Much like the old-style file manager, it has 3 levels of flexibility for its methods -
304 // Low - which means you have to iterate yourself through the mime database
305 // Medium - which lets you sort of cache the database if you want to use lowlevel functions
306 // High - which requires access to the database every time
308 // We want to be efficient (i.e. professional :) ) about it, so we use a combo of low
309 // and mid-level functions
311 // TODO: Should we call ICBegin/ICEnd? Then where?
315 inline void wxLogMimeDebug(const wxChar
* szMsg
, OSStatus status
)
317 wxLogDebug(wxString::Format(wxT("%s LINE:%i OSERROR:%i"), szMsg
, __LINE__
, (int)status
));
320 // in case we're compiling in non-GUI mode
321 class WXDLLEXPORT wxIcon
;
323 bool wxFileTypeImpl::SetCommand(const wxString
& cmd
, const wxString
& verb
, bool overwriteprompt
)
328 bool wxFileTypeImpl::SetDefaultIcon(const wxString
& strIcon
, int index
)
333 bool wxFileTypeImpl::GetOpenCommand(wxString
*openCmd
,
334 const wxFileType::MessageParameters
& params
) const
336 wxString cmd
= GetCommand(wxT("open"));
338 *openCmd
= wxFileType::ExpandCommand(cmd
, params
);
340 return !openCmd
->empty();
344 wxFileTypeImpl::GetPrintCommand(wxString
*printCmd
,
345 const wxFileType::MessageParameters
& params
)
348 wxString cmd
= GetCommand(wxT("print"));
350 *printCmd
= wxFileType::ExpandCommand(cmd
, params
);
352 return !printCmd
->empty();
356 // Internet Config vs. Launch Services
358 // From OS 8 on there was internet config...
359 // However, OSX and its finder does not use info
360 // from Internet Config at all - the Internet Config
361 // database ONLY CONTAINS APPS THAT ARE CLASSIC APPS
362 // OR REGISTERED THROUGH INTERNET CONFIG
364 // Therefore on OSX in order for the open command to be useful
365 // we need to go straight to launch services
368 #if defined(__DARWIN__)
370 //on darwin, use launch services
371 #include "LaunchServices.h"
373 wxString
wxFileTypeImpl::GetCommand(const wxString
& verb
) const
378 return wxEmptyString
;
380 if(verb
== wxT("open"))
383 ICGetMapEntry( (ICInstance
) m_manager
->m_hIC
,
384 (Handle
) m_manager
->m_hDatabase
,
387 wxString sCurrentExtension
= wxMacMakeStringFromPascal(entry
.extension
);
388 sCurrentExtension
= sCurrentExtension
.Right(sCurrentExtension
.Length()-1 );
390 //type, creator, ext, roles, outapp (FSRef), outappurl
391 CFURLRef cfurlAppPath
;
392 OSStatus status
= LSGetApplicationForInfo (kLSUnknownType
,
394 wxMacCFStringHolder(sCurrentExtension
, wxLocale::GetSystemEncoding()),
401 CFStringRef cfsUnixPath
= CFURLCopyFileSystemPath(cfurlAppPath
, kCFURLPOSIXPathStyle
);
402 CFRelease(cfurlAppPath
);
406 return wxMacCFStringHolder(cfsUnixPath
).AsString(wxLocale::GetSystemEncoding());
410 wxLogDebug(wxString::Format(wxT("%i - %s - %i"),
412 wxT("LSGetApplicationForInfo failed."),
417 return wxEmptyString
;
420 #else //carbon/classic implementation
422 wxString
wxFileTypeImpl::GetCommand(const wxString
& verb
) const
427 return wxEmptyString
;
429 if(verb
== wxT("open"))
432 ICGetMapEntry( (ICInstance
) m_manager
->m_hIC
,
433 (Handle
) m_manager
->m_hDatabase
,
436 //The entry in the mimetype database only contains the app
437 //that's registered - it may not exist... we need to remap the creator
438 //type and find the right application
440 // THIS IS REALLY COMPLICATED :\. There are a lot of conversions going
444 if(FindApplication(entry
.fileCreator
, false, outName
, &outSpec
) != noErr
)
445 return wxEmptyString
;
447 Handle outPathHandle
;
449 OSErr err
= FSpGetFullPath(&outSpec
, &outPathSize
, &outPathHandle
);
453 char* szPath
= *outPathHandle
;
454 wxString
sClassicPath(szPath
, wxConvLocal
, outPathSize
);
455 #if defined(__DARWIN__)
456 //Classic Path --> Unix (OSX) Path
457 CFURLRef finalURL
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
,
458 wxMacCFStringHolder(sClassicPath
, wxLocale::GetSystemEncoding()),
460 false); //false == not a directory
462 //clean up memory from the classic path handle
463 DisposeHandle(outPathHandle
);
467 CFStringRef cfsUnixPath
= CFURLCopyFileSystemPath(finalURL
, kCFURLPOSIXPathStyle
);
472 return wxMacCFStringHolder(cfsUnixPath
).AsString(wxLocale::GetSystemEncoding());
474 #else //classic HFS path acceptable
480 wxLogMimeDebug(wxT("FSpGetFullPath failed."), (OSStatus
)err
);
483 return wxEmptyString
;
487 bool wxFileTypeImpl::GetExtensions(wxArrayString
& extensions
)
493 ICGetMapEntry( (ICInstance
) m_manager
->m_hIC
,
494 (Handle
) m_manager
->m_hDatabase
,
497 //entry has period in it
498 wxString sCurrentExtension
= wxMacMakeStringFromPascal(entry
.extension
);
499 extensions
.Add( sCurrentExtension
.Right(sCurrentExtension
.Length()-1) );
503 bool wxFileTypeImpl::GetMimeType(wxString
*mimeType
) const
509 ICGetMapEntry( (ICInstance
) m_manager
->m_hIC
,
510 (Handle
) m_manager
->m_hDatabase
,
513 *mimeType
= wxMacMakeStringFromPascal(entry
.MIMEType
);
517 bool wxFileTypeImpl::GetMimeTypes(wxArrayString
& mimeTypes
) const
531 bool wxFileTypeImpl::GetIcon(wxIconLocation
*WXUNUSED(icon
)) const
533 // no such file type or no value or incorrect icon entry
537 bool wxFileTypeImpl::GetDescription(wxString
*desc
) const
543 ICGetMapEntry( (ICInstance
) m_manager
->m_hIC
,
544 (Handle
) m_manager
->m_hDatabase
,
547 *desc
= wxString((char*)entry
.entryName
, wxConvLocal
);
551 size_t wxFileTypeImpl::GetAllCommands(wxArrayString
* verbs
, wxArrayString
* commands
,
552 const wxFileType::MessageParameters
& params
) const
554 wxFAIL_MSG( _T("wxFileTypeImpl::GetAllCommands() not yet implemented") );
558 void wxMimeTypesManagerImpl::Initialize(int mailcapStyles
, const wxString
& extraDir
)
560 wxASSERT_MSG(m_hIC
== NULL
, wxT("Already initialized wxMimeTypesManager!"));
562 //start internet config - log if there's an error
563 //the second param is the signature of the application, also known
564 //as resource ID 0. However, as per some recent discussions, we may not
565 //have a signature for this app, so a generic 'APPL' which is the executable
566 //type will work for now
567 OSStatus status
= ICStart( (ICInstance
*) &m_hIC
, 'APPL');
571 wxLogDebug(wxT("Could not initialize wxMimeTypesManager!"));
577 m_hDatabase
= (void**) NewHandle(0);
578 status
= ICFindPrefHandle( (ICInstance
) m_hIC
, kICMapping
, &attr
, (Handle
) m_hDatabase
);
580 //the database file can be corrupt (on OSX its
581 //~/Library/Preferences/com.apple.internetconfig.plist)
586 wxLogDebug(wxT("Corrupt Mime Database!"));
590 //obtain the number of entries in the map
591 status
= ICCountMapEntries( (ICInstance
) m_hIC
, (Handle
) m_hDatabase
, &m_lCount
);
592 wxASSERT( status
== noErr
);
598 for(long i = 1; i <= m_lCount; ++i)
600 OSStatus status = ICGetIndMapEntry( (ICInstance) m_hIC, (Handle) m_hDatabase, i, &pos, &entry);
604 wxString sCreator = wxMacMakeStringFromPascal(entry.creatorAppName);
605 wxString sCurrentExtension = wxMacMakeStringFromPascal(entry.extension);
606 wxString sMIMEType = wxMacMakeStringFromPascal(entry.MIMEType);
609 impl.Init(this, pos);
611 if(sMIMEType == wxT("text/html") && sCurrentExtension == wxT(".html"))
614 impl.GetOpenCommand (&cmd,
615 wxFileType::MessageParameters (wxT("http://www.google.com"),
618 wxPrintf(wxT("APP: [%s]\n"), cmd.c_str());
625 void wxMimeTypesManagerImpl::ClearData()
629 DisposeHandle((Handle
)m_hDatabase
);
630 //this can return an error, but we don't really care that much about it
631 ICStop( (ICInstance
) m_hIC
);
636 // extension -> file type
637 wxFileType
* wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString
& e
)
639 wxASSERT_MSG( m_hIC
!= NULL
, wxT("wxMimeTypesManager not Initialized!") );
641 //low level functions - iterate through the database
643 wxFileType
* pFileType
;
646 for(long i
= 1; i
<= m_lCount
; ++i
)
648 OSStatus status
= ICGetIndMapEntry( (ICInstance
) m_hIC
, (Handle
) m_hDatabase
, i
, &pos
, &entry
);
652 wxString sCurrentExtension
= wxMacMakeStringFromPascal(entry
.extension
);
653 if( sCurrentExtension
.Right(sCurrentExtension
.Length()-1) == e
) //entry has period in it
655 pFileType
= new wxFileType();
656 pFileType
->m_impl
->Init((wxMimeTypesManagerImpl
*)this, pos
);
665 // MIME type -> extension -> file type
666 wxFileType
* wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString
& mimeType
)
668 wxASSERT_MSG( m_hIC
!= NULL
, wxT("wxMimeTypesManager not Initialized!") );
670 //low level functions - iterate through the database
672 wxFileType
* pFileType
;
676 for(long i
= 1; i
<= m_lCount
; ++i
)
678 OSStatus status
= ICGetIndMapEntry( (ICInstance
) m_hIC
, (Handle
) m_hDatabase
, i
, &pos
, &entry
);
679 wxASSERT_MSG( status
== noErr
, wxString::Format(wxT("Error: %d"), (int)status
) );
683 if( wxMacMakeStringFromPascal(entry
.MIMEType
) == mimeType
)
685 pFileType
= new wxFileType();
686 pFileType
->m_impl
->Init((wxMimeTypesManagerImpl
*)this, pos
);
695 size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxArrayString
& mimetypes
)
697 wxASSERT_MSG( m_hIC
!= NULL
, wxT("wxMimeTypesManager not Initialized!") );
699 //low level functions - iterate through the database
703 long lStartCount
= (long) mimetypes
.GetCount();
705 for(long i
= 1; i
<= m_lCount
; ++i
)
707 OSStatus status
= ICGetIndMapEntry( (ICInstance
) m_hIC
, (Handle
) m_hDatabase
, i
, &pos
, &entry
);
708 if( status
== noErr
)
709 mimetypes
.Add( wxMacMakeStringFromPascal(entry
.MIMEType
) );
712 return mimetypes
.GetCount() - lStartCount
;
716 pascal OSStatus
MoreProcGetProcessTypeSignature(
717 const ProcessSerialNumberPtr pPSN
,
718 OSType
*pProcessType
,
721 OSStatus anErr
= noErr
;
722 ProcessInfoRec infoRec
;
723 ProcessSerialNumber localPSN
;
725 infoRec
.processInfoLength
= sizeof(ProcessInfoRec
);
726 infoRec
.processName
= nil
;
727 infoRec
.processAppSpec
= nil
;
730 localPSN
.highLongOfPSN
= 0;
731 localPSN
.lowLongOfPSN
= kCurrentProcess
;
736 anErr
= GetProcessInformation(&localPSN
, &infoRec
);
739 *pProcessType
= infoRec
.processType
;
740 *pCreator
= infoRec
.processSignature
;
744 }//end MoreProcGetProcessTypeSignature
747 wxMimeTypesManagerImpl::Associate(const wxFileTypeInfo
& ftInfo
)
750 wxFAIL_MSG(wxT("Associate not ready for production use"));
753 //on mac you have to embed it into the mac's file reference resource ('FREF' I believe)
754 //or, alternately, you could just add an entry to m_hDatabase, but you'd need to get
755 //the app's signature somehow...
759 OSStatus status
= MoreProcGetProcessTypeSignature(NULL
,&processType
, &creator
);
763 Str255 psCreatorName
;
765 status
= FindApplication(creator
, false, psCreatorName
, &dummySpec
);
770 //get the file type if it exists -
771 //if it really does then modify the database then save it,
772 //otherwise we need to create a whole new entry
773 wxFileType
* pFileType
= GetFileTypeFromMimeType(ftInfo
.GetMimeType());
777 ICGetMapEntry( (ICInstance
) m_hIC
, (Handle
) m_hDatabase
,
778 pFileType
->m_impl
->m_lIndex
, &entry
);
780 entry
.creatorAppName
= psCreatorName
;
781 entry
.fileCreator
= creator
;
783 status
= ICSetMapEntry( (ICInstance
) m_hIC
, (Handle
) m_hDatabase
,
784 pFileType
->m_impl
->m_lIndex
, &entry
);
791 wxLogDebug(wxString::Format(wxT("%i - %s"), __LINE__
, wxT("ICSetMapEntry failed.")));
799 //TODO: Maybe force all 3 of these to be non-empty?
802 Str255 psDescription
;
804 wxMacStringToPascal(ftInfo
.GetExtensions()[0], psExtension
);
805 wxMacStringToPascal(ftInfo
.GetMimeType(), psMimeType
);
806 wxMacStringToPascal(ftInfo
.GetDescription(), psDescription
);
808 Str255 psPostCreatorName
;
809 wxMacStringToPascal(wxT(""), psPostCreatorName
);
812 //add the entry to the database
813 //TODO: Does this work?
815 entry
.totalLength
= sizeof(ICMapEntry
);
816 entry
.fixedLength
= kICMapFixedLength
;
818 entry
.fileType
= 0; //TODO: File type?
819 entry
.fileCreator
= creator
;
820 entry
.postCreator
= 0;
821 entry
.flags
= kICMapDataForkBit
; //TODO: Maybe resource is valid by default too?
822 entry
.extension
= psExtension
;
823 entry
.creatorAppName
= psCreatorName
;
824 entry
.postAppName
= psPostCreatorName
;
825 entry
.MIMEType
= psMimeType
;
826 entry
.entryName
= psDescription
;
828 status
= ICAddMapEntry( (ICInstance
) m_hIC
, (Handle
) m_hDatabase
, &entry
);
832 //kICAttrNoChange means we don't care about attributes such as
833 //locking in the database
834 status
= ICSetPrefHandle((ICInstance
) m_hIC
, kICMapping
,
835 kICAttrNoChange
, (Handle
) m_hDatabase
);
837 //return the entry in the database if successful
839 return GetFileTypeFromMimeType(ftInfo
.GetMimeType());
842 wxLogDebug(wxString::Format(wxT("%i - %s"), __LINE__
, wxT("ICSetPrefHandle failed.")));
847 wxLogDebug(wxString::Format(wxT("%i - %s"), __LINE__
, wxT("ICAppMapEntry failed.")));
850 } //end if FindApplcation was successful
853 wxLogDebug(wxString::Format(wxT("%i - %s"), __LINE__
, wxT("FindApplication failed.")));
855 } //end if it could obtain app's signature
858 wxLogDebug(wxString::Format(wxT("%i - %s"), __LINE__
, wxT("GetProcessSignature failed.")));
865 wxMimeTypesManagerImpl::Unassociate(wxFileType
*pFileType
)
868 wxFAIL_MSG(wxT("Unassociate not ready for production use"));
871 //this should be as easy as removing the entry from the database and then saving
873 OSStatus status
= ICDeleteMapEntry( (ICInstance
) m_hIC
, (Handle
) m_hDatabase
,
874 pFileType
->m_impl
->m_lIndex
);
878 //kICAttrNoChange means we don't care about attributes such as
879 //locking in the database
880 status
= ICSetPrefHandle((ICInstance
) m_hIC
, kICMapping
,
881 kICAttrNoChange
, (Handle
) m_hDatabase
);
887 wxLogDebug(wxString::Format(wxT("%i - %s"), __LINE__
, wxT("ICSetPrefHandle failed.")));
893 wxLogDebug(wxString::Format(wxT("%i - %s"), __LINE__
, wxT("ICDeleteMapEntry failed.")));
900 #endif //wxUSE_MIMETYPE