📄 mimetmac.cpp
字号:
/////////////////////////////////////////////////////////////////////////////// Name: src/mac/carbon/mimetype.cpp// Purpose: Mac Carbon implementation for wx MIME-related classes// Author: Ryan Norton// Modified by:// Created: 04/16/2005// RCS-ID: $Id: mimetmac.cpp,v 1.40 2006/10/14 16:33:30 SC Exp $// Copyright: (c) 2005 Ryan Norton (<wxprojects@comcast.net>)// Licence: wxWindows licence///////////////////////////////////////////////////////////////////////////////// TODO: Search Info[-macos](classic).plist dictionary in addition// to Internet Config database.//// Maybe try a brainstorm a way to change the wxMimeTypesManager API// to get info from a file instead/addition to current get all stuff// API so that we can use Launch Services to get MIME type info.//// Implement GetIcon from one of the FinderInfo functions - or// use Launch Services and search that app's plist for the icon.//// Put some special juice in for the print command.//// for compilers that support precompilation, includes "wx.h".#include "wx/wxprec.h"#ifdef __BORLANDC__ #pragma hdrstop#endif#if wxUSE_MIMETYPE#include "wx/mac/mimetype.h"#ifndef WX_PRECOMP #include "wx/dynarray.h" #include "wx/string.h" #include "wx/intl.h" #include "wx/log.h" #if wxUSE_GUI #include "wx/icon.h" #endif#endif#include "wx/file.h"#include "wx/confbase.h"#include "wx/mac/private.h"// other standard headers#include <ctype.h>#ifndef __DARWIN__ #include <InternetConfig.h> #include <CoreServices.h>#endif#ifndef __LP64__// START CODE SAMPLE FROM TECHNOTE 1002 (http://developer.apple.com/technotes/tn/tn1002.html)// IsRemoteVolume can be used to find out if the// volume referred to by vRefNum is a remote volume// located somewhere on a network. the volume's attribute// flags (copied from the GetVolParmsInfoBuffer structure)// are returned in the longword pointed to by vMAttrib.OSErr IsRemoteVolume(short vRefNum, Boolean *isRemote, long *vMAttrib){ HParamBlockRec volPB; GetVolParmsInfoBuffer volinfo; OSErr err; volPB.ioParam.ioVRefNum = vRefNum; volPB.ioParam.ioNamePtr = NULL; volPB.ioParam.ioBuffer = (Ptr)&volinfo; volPB.ioParam.ioReqCount = sizeof(volinfo); err = PBHGetVolParmsSync( &volPB ); if (err == noErr) { *isRemote = (volinfo.vMServerAdr != 0); *vMAttrib = volinfo.vMAttrib; } return err;}// BuildVolumeList fills the array pointed to by vols with// a list of the currently mounted volumes. If includeRemote// is true, then remote server volumes will be included in// the list. When remote server volumes are included in the// list, they will be added to the end of the list. On entry,// *count should contain the size of the array pointed to by// vols. On exit, *count will be set to the number of id numbers// placed in the array. If vMAttribMask is non-zero, then// only volumes with matching attributes are added to the// list of volumes. bits in the vMAttribMask should use the// same encoding as bits in the vMAttrib field of// the GetVolParmsInfoBuffer structure.OSErr BuildVolumeList(Boolean includeRemote, short *vols, long *count, long vMAttribMask){ HParamBlockRec volPB; Boolean isRemote; OSErr err = noErr; long nlocal, nremote; long vMAttrib; // set up and check parameters volPB.volumeParam.ioNamePtr = NULL; nlocal = nremote = 0; if (*count == 0) return noErr; // iterate through volumes for (volPB.volumeParam.ioVolIndex = 1; PBHGetVInfoSync(&volPB) == noErr; volPB.volumeParam.ioVolIndex++) { // skip remote volumes, if necessary err = IsRemoteVolume(volPB.volumeParam.ioVRefNum, &isRemote, &vMAttrib); if (err != noErr) goto bail; if ((includeRemote || !isRemote) && ((vMAttrib & vMAttribMask) == vMAttribMask)) { // add local volumes at the front; remote volumes at the end if (isRemote) vols[nlocal + nremote++] = volPB.volumeParam.ioVRefNum; else { if (nremote > 0) BlockMoveData( vols + nlocal, vols + nlocal + 1, nremote * sizeof(short) ); vols[nlocal++] = volPB.volumeParam.ioVRefNum; } // list full? if ((nlocal + nremote) >= *count) break; } }bail: *count = (nlocal + nremote); return err;}// FindApplication iterates through mounted volumes// searching for an application with the given creator// type. If includeRemote is true, then remote volumes// will be searched (after local ones) for an application// with the creator type.//// Hacked to output to appName//#define kMaxVols 20OSErr FindApplication(OSType appCreator, Boolean includeRemote, Str255 appName, FSSpec* appSpec){ short rRefNums[kMaxVols]; long i, volCount; DTPBRec desktopPB; OSErr err; // get a list of volumes - with desktop files volCount = kMaxVols; err = BuildVolumeList(includeRemote, rRefNums, &volCount, (1 << bHasDesktopMgr) ); if (err != noErr) return err; // iterate through the list for (i=0; i<volCount; i++) { // has a desktop file? desktopPB.ioCompletion = NULL; desktopPB.ioVRefNum = rRefNums[i]; desktopPB.ioNamePtr = NULL; desktopPB.ioIndex = 0; err = PBDTGetPath( &desktopPB ); if (err != noErr) continue; // has the correct app?? desktopPB.ioFileCreator = appCreator; desktopPB.ioNamePtr = appName; err = PBDTGetAPPLSync( &desktopPB ); if (err != noErr) continue; // make a file spec referring to it err = FSMakeFSSpec( rRefNums[i], desktopPB.ioAPPLParID, appName, appSpec ); if (err != noErr) continue; // found it! return noErr; } return fnfErr;}// END CODE SAMPLE FROM TECHNOTE 1002 (http://developer.apple.com/technotes/tn/tn1002.html)// yeah, duplicated codepascal OSErr FSpGetFullPath( const FSSpec *spec, short *fullPathLength, Handle *fullPath ){ OSErr result, realResult; FSSpec tempSpec; CInfoPBRec pb; *fullPathLength = 0; *fullPath = NULL; // default to noErr realResult = result = noErr; // work around Nav Services "bug" (it returns invalid FSSpecs with empty names)#if 0 if ( spec->name[0] == 0 ) { result = FSMakeFSSpecCompat(spec->vRefNum, spec->parID, spec->name, &tempSpec); } else {#endif // Make a copy of the input FSSpec that can be modified BlockMoveData( spec, &tempSpec, sizeof(FSSpec) ); if ( result == noErr ) { if ( tempSpec.parID == fsRtParID ) { // object is a volume // Add a colon to make it a full pathname ++tempSpec.name[0]; tempSpec.name[tempSpec.name[0]] = ':'; // We're done result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]); } else { // object isn't a volume // Is the object a file or a directory? pb.dirInfo.ioNamePtr = tempSpec.name; pb.dirInfo.ioVRefNum = tempSpec.vRefNum; pb.dirInfo.ioDrDirID = tempSpec.parID; pb.dirInfo.ioFDirIndex = 0; result = PBGetCatInfoSync( &pb ); // Allow file/directory name at end of path to not exist. realResult = result; if ((result == noErr) || (result == fnfErr)) { // if the object is a directory, append a colon so full pathname ends with colon if ((result == noErr) && (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0) { ++tempSpec.name[0]; tempSpec.name[tempSpec.name[0]] = ':'; } // Put the object name in first result = PtrToHand( &tempSpec.name[1], fullPath, tempSpec.name[0] ); if ( result == noErr ) { // Get the ancestor directory names pb.dirInfo.ioNamePtr = tempSpec.name; pb.dirInfo.ioVRefNum = tempSpec.vRefNum; pb.dirInfo.ioDrParID = tempSpec.parID; // loop until we have an error or find the root directory do { pb.dirInfo.ioFDirIndex = -1; pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID; result = PBGetCatInfoSync(&pb); if ( result == noErr ) { // Append colon to directory name ++tempSpec.name[0]; tempSpec.name[tempSpec.name[0]] = ':'; // Add directory name to beginning of fullPath (void)Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1], tempSpec.name[0]); result = MemError(); } } while ( (result == noErr) && (pb.dirInfo.ioDrDirID != fsRtDirID) ); } } } } if ( result == noErr ) { // Return the length *fullPathLength = GetHandleSize( *fullPath ); result = realResult; // return realResult in case it was fnfErr } else { // Dispose of the handle and return NULL and zero length if ( *fullPath != NULL ) { DisposeHandle( *fullPath ); *fullPath = NULL; } *fullPathLength = 0; } return result;}#endif//// On the mac there are two ways to open a file - one is through apple events and the// finder, another is through mime types.//// So, really there are two ways to implement wxFileType...//// Mime types are only available on OS 8.1+ through the InternetConfig API//// Much like the old-style file manager, it has 3 levels of flexibility for its methods -// Low - which means you have to iterate yourself through the mime database// Medium - which lets you sort of cache the database if you want to use lowlevel functions// High - which requires access to the database every time//// We want to be efficient (i.e. professional :) ) about it, so we use a combo of low// and mid-level functions//// TODO: Should we call ICBegin/ICEnd? Then where?//// debug helperinline void wxLogMimeDebug(const wxChar* szMsg, OSStatus status){ wxLogDebug(wxString::Format(wxT("%s LINE:%i OSERROR:%i"), szMsg, __LINE__, (int)status));}// in case we're compiling in non-GUI modeclass WXDLLEXPORT wxIcon;bool wxFileTypeImpl::SetCommand(const wxString& cmd, const wxString& verb, bool overwriteprompt){ wxASSERT_MSG( m_manager != NULL , wxT("Bad wxFileType") ); return false;}bool wxFileTypeImpl::SetDefaultIcon(const wxString& strIcon, int index){ wxASSERT_MSG( m_manager != NULL , wxT("Bad wxFileType") ); return false;}bool wxFileTypeImpl::GetOpenCommand(wxString *openCmd, const wxFileType::MessageParameters& params) const{ wxString cmd = GetCommand(wxT("open")); *openCmd = wxFileType::ExpandCommand(cmd, params); return !openCmd->empty();}boolwxFileTypeImpl::GetPrintCommand( wxString *printCmd, const wxFileType::MessageParameters& params) const{ wxString cmd = GetCommand(wxT("print")); *printCmd = wxFileType::ExpandCommand(cmd, params); return !printCmd->empty();}//// Internet Config vs. Launch Services//// From OS 8 on there was internet config...// However, OSX and its finder does not use info// from Internet Config at all - the Internet Config// database ONLY CONTAINS APPS THAT ARE CLASSIC APPS// OR REGISTERED THROUGH INTERNET CONFIG//// Therefore on OSX in order for the open command to be useful// we need to go straight to launch services//#if defined(__DARWIN__)//on darwin, use launch services#include <ApplicationServices/ApplicationServices.h>wxString wxFileTypeImpl::GetCommand(const wxString& verb) const{ wxASSERT_MSG( m_manager != NULL , wxT("Bad wxFileType") ); if (verb == wxT("open")) { ICMapEntry entry; ICGetMapEntry( (ICInstance) m_manager->m_hIC, (Handle) m_manager->m_hDatabase,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -