]> git.saurik.com Git - wxWidgets.git/blob - src/mac/corefoundation/utilsexc_base.cpp
patch 1265473
[wxWidgets.git] / src / mac / corefoundation / utilsexc_base.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: mac/corefoundation/utilsexc_base.cpp
3 // Purpose: wxMacExecute
4 // Author: Ryan Norton
5 // Modified by:
6 // Created: 2005-06-21
7 // RCS-ID: $Id$
8 // Copyright: (c) Ryan Norton
9 // Licence: wxWindows licence
10 // Notes: Source was originally in utilsexc_cf.cpp,1.6 then moved
11 // to totally unrelated hid.cpp,1.8.
12 /////////////////////////////////////////////////////////////////////////////
13
14 //===========================================================================
15 // DECLARATIONS
16 //===========================================================================
17
18 //---------------------------------------------------------------------------
19 // Pre-compiled header stuff
20 //---------------------------------------------------------------------------
21
22 // For compilers that support precompilation, includes "wx.h".
23 #include "wx/wxprec.h"
24
25 // WX includes
26 #ifndef WX_PRECOMP
27 #include "wx/string.h"
28 #include "wx/log.h"
29 #include "wx/intl.h"
30 #include "wx/utils.h"
31 #endif // WX_PRECOMP
32
33 // Mac Includes
34 #include <CoreFoundation/CoreFoundation.h>
35 #include <ApplicationServices/ApplicationServices.h>
36
37 // More WX Includes
38 #include "wx/filename.h"
39 #include "wx/mac/corefoundation/cfstring.h"
40
41 // Default path style
42 #ifdef __WXMAC_OSX__
43 #define kDefaultPathStyle kCFURLPOSIXPathStyle
44 #else
45 #define kDefaultPathStyle kCFURLHFSPathStyle
46 #endif
47
48 //===========================================================================
49 // IMPLEMENTATION
50 //===========================================================================
51
52 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
53 //
54 // wxMacExecute
55 //
56 // argv is the command line split up, with the application path first
57 // flags are the flags from wxExecute
58 // process is the process passed from wxExecute for pipe streams etc.
59 // returns -1 on error for wxEXEC_SYNC and 0 on error for wxEXEC_ASYNC
60 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
61 long wxMacExecute(wxChar **argv,
62 int flags,
63 wxProcess *process)
64 {
65 // Semi-macros used for return value of wxMacExecute
66 const long errorCode = ((flags & wxEXEC_SYNC) ? -1 : 0);
67 const long successCode = ((flags & wxEXEC_SYNC) ? 0 : -1); // fake PID
68
69 // Obtains the number of arguments for determining the size of
70 // the CFArray used to hold them
71 CFIndex cfiCount = 0;
72 for(wxChar** argvcopy = argv; *argvcopy != NULL ; ++argvcopy)
73 {
74 ++cfiCount;
75 }
76
77 // If there is not a single argument then there is no application
78 // to launch
79 if(cfiCount == 0)
80 {
81 wxLogDebug(wxT("wxMacExecute No file to launch!"));
82 return errorCode ;
83 }
84
85 // Path to bundle
86 wxString path = *argv++;
87
88 // Create a CFURL for the application path
89 // Created this way because we are opening a bundle which is a directory
90 CFURLRef cfurlApp =
91 CFURLCreateWithFileSystemPath(
92 kCFAllocatorDefault,
93 wxMacCFStringHolder(path,
94 wxLocale::GetSystemEncoding()),
95 kDefaultPathStyle,
96 true); //false == not a directory
97
98 // Check for error from the CFURL
99 if(!cfurlApp)
100 {
101 wxLogDebug(wxT("wxMacExecute Can't open path: %s"), path.c_str());
102 return errorCode ;
103 }
104
105 // Create a CFBundle from the CFURL created earlier
106 CFBundleRef cfbApp = CFBundleCreate(kCFAllocatorDefault, cfurlApp);
107
108 // Check to see if CFBundleCreate returned an error,
109 // and if it did this was an invalid bundle or not a bundle
110 // at all (maybe a simple directory etc.)
111 if(!cfbApp)
112 {
113 wxLogDebug(wxT("wxMacExecute Bad bundle: %s"), path.c_str());
114 CFRelease(cfurlApp);
115 return errorCode ;
116 }
117
118 // Get the bundle type and make sure its an 'APPL' bundle
119 // Otherwise we're dealing with something else here...
120 UInt32 dwBundleType, dwBundleCreator;
121 CFBundleGetPackageInfo(cfbApp, &dwBundleType, &dwBundleCreator);
122 if(dwBundleType != 'APPL')
123 {
124 wxLogDebug(wxT("wxMacExecute Not an APPL bundle: %s"), path.c_str());
125 CFRelease(cfbApp);
126 CFRelease(cfurlApp);
127 return errorCode ;
128 }
129
130 // Create a CFArray for dealing with the command line
131 // arguments to the bundle
132 CFMutableArrayRef cfaFiles = CFArrayCreateMutable(kCFAllocatorDefault,
133 cfiCount-1, &kCFTypeArrayCallBacks);
134 if(!cfaFiles) //This should never happen
135 {
136 wxLogDebug(wxT("wxMacExecute Could not create CFMutableArray"));
137 CFRelease(cfbApp);
138 CFRelease(cfurlApp);
139 return errorCode ;
140 }
141
142 // Loop through command line arguments to the bundle,
143 // turn them into CFURLs and then put them in cfaFiles
144 // For use to launch services call
145 for( ; *argv != NULL ; ++argv)
146 {
147 // Check for '<' as this will ring true for
148 // CFURLCreateWithString but is generally not considered
149 // typical on mac but is usually passed here from wxExecute
150 if (wxStrcmp(*argv, wxT("<")) == 0)
151 continue;
152
153
154 CFURLRef cfurlCurrentFile; // CFURL to hold file path
155 wxFileName argfn(*argv); // Filename for path
156
157 if(argfn.DirExists())
158 {
159 // First, try creating as a directory
160 cfurlCurrentFile = CFURLCreateWithFileSystemPath(
161 kCFAllocatorDefault,
162 wxMacCFStringHolder(*argv,
163 wxLocale::GetSystemEncoding()),
164 kDefaultPathStyle,
165 true); //true == directory
166 }
167 else if(argfn.FileExists())
168 {
169 // And if it isn't a directory try creating it
170 // as a regular file
171 cfurlCurrentFile = CFURLCreateWithFileSystemPath(
172 kCFAllocatorDefault,
173 wxMacCFStringHolder(*argv,
174 wxLocale::GetSystemEncoding()),
175 kDefaultPathStyle,
176 false); //false == regular file
177 }
178 else
179 {
180 // Argument did not refer to
181 // an entry in the local filesystem,
182 // so try creating it through CFURLCreateWithString
183 cfurlCurrentFile = CFURLCreateWithString(
184 kCFAllocatorDefault,
185 wxMacCFStringHolder(*argv, wxLocale::GetSystemEncoding()),
186 NULL);
187 }
188
189 // Continue in the loop if the CFURL could not be created
190 if(!cfurlCurrentFile)
191 {
192 wxLogDebug(
193 wxT("wxMacExecute Could not create CFURL for argument:%s"),
194 *argv);
195 continue;
196 }
197
198 // Add the valid CFURL to the argument array and then
199 // release it as the CFArray adds a ref count to it
200 CFArrayAppendValue(
201 cfaFiles,
202 cfurlCurrentFile
203 );
204 CFRelease(cfurlCurrentFile); // array has retained it
205 }
206
207 // Create a LSLaunchURLSpec for use with LSOpenFromURLSpec
208 // Note that there are several flag options (launchFlags) such
209 // as kLSLaunchDontSwitch etc. and maybe we could be more
210 // picky about the flags we choose
211 LSLaunchURLSpec launchspec;
212 launchspec.appURL = cfurlApp;
213 launchspec.itemURLs = cfaFiles;
214 launchspec.passThruParams = NULL; //AEDesc*
215 launchspec.launchFlags = kLSLaunchDefaults;
216 launchspec.asyncRefCon = NULL;
217
218 // Finally, call LSOpenFromURL spec with our arguments
219 // 2nd parameter is a pointer to a CFURL that gets
220 // the actual path launched by the function
221 OSStatus status = LSOpenFromURLSpec(&launchspec, NULL);
222
223 // Cleanup corefoundation references
224 CFRelease(cfbApp);
225 CFRelease(cfurlApp);
226 CFRelease(cfaFiles);
227
228 // Check for error from LSOpenFromURLSpec
229 if(status != noErr)
230 {
231 wxLogDebug(wxT("wxMacExecute LSOpenFromURLSpec Error: %d"),
232 (int)status);
233 return errorCode ;
234 }
235
236 // No error from LSOpenFromURLSpec, so app was launched
237 return successCode;
238 }
239