]>
Commit | Line | Data |
---|---|---|
1ccb7433 DE |
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 | ||
7db33dd7 SC |
14 | //=========================================================================== |
15 | // DECLARATIONS | |
16 | //=========================================================================== | |
17 | ||
18 | //--------------------------------------------------------------------------- | |
19 | // Pre-compiled header stuff | |
20 | //--------------------------------------------------------------------------- | |
21 | ||
1ccb7433 DE |
22 | // For compilers that support precompilation, includes "wx.h". |
23 | #include "wx/wxprec.h" | |
7db33dd7 SC |
24 | |
25 | // WX includes | |
1ccb7433 DE |
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 | ||
7db33dd7 | 33 | // Mac Includes |
1ccb7433 DE |
34 | #include <CoreFoundation/CoreFoundation.h> |
35 | #include <ApplicationServices/ApplicationServices.h> | |
36 | ||
7db33dd7 SC |
37 | // More WX Includes |
38 | #include "wx/filename.h" | |
1ccb7433 DE |
39 | #include "wx/mac/corefoundation/cfstring.h" |
40 | ||
7db33dd7 SC |
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 | //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
1ccb7433 DE |
61 | long wxMacExecute(wxChar **argv, |
62 | int flags, | |
63 | wxProcess *process) | |
64 | { | |
7db33dd7 | 65 | // Semi-macros used for return value of wxMacExecute |
1ccb7433 DE |
66 | const long errorCode = ((flags & wxEXEC_SYNC) ? -1 : 0); |
67 | const long successCode = ((flags & wxEXEC_SYNC) ? 0 : -1); // fake PID | |
68 | ||
7db33dd7 SC |
69 | // Obtains the number of arguments for determining the size of |
70 | // the CFArray used to hold them | |
1ccb7433 | 71 | CFIndex cfiCount = 0; |
1ccb7433 DE |
72 | for(wxChar** argvcopy = argv; *argvcopy != NULL ; ++argvcopy) |
73 | { | |
74 | ++cfiCount; | |
75 | } | |
76 | ||
7db33dd7 SC |
77 | // If there is not a single argument then there is no application |
78 | // to launch | |
79 | if(cfiCount == 0) | |
1ccb7433 DE |
80 | { |
81 | wxLogDebug(wxT("wxMacExecute No file to launch!")); | |
82 | return errorCode ; | |
83 | } | |
84 | ||
7db33dd7 SC |
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( | |
1ccb7433 | 92 | kCFAllocatorDefault, |
7db33dd7 SC |
93 | wxMacCFStringHolder(path, |
94 | wxLocale::GetSystemEncoding()), | |
95 | kDefaultPathStyle, | |
96 | true); //false == not a directory | |
1ccb7433 | 97 | |
7db33dd7 SC |
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 | |
1ccb7433 | 106 | CFBundleRef cfbApp = CFBundleCreate(kCFAllocatorDefault, cfurlApp); |
7db33dd7 SC |
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.) | |
1ccb7433 DE |
111 | if(!cfbApp) |
112 | { | |
7db33dd7 | 113 | wxLogDebug(wxT("wxMacExecute Bad bundle: %s"), path.c_str()); |
1ccb7433 DE |
114 | CFRelease(cfurlApp); |
115 | return errorCode ; | |
116 | } | |
117 | ||
7db33dd7 SC |
118 | // Get the bundle type and make sure its an 'APPL' bundle |
119 | // Otherwise we're dealing with something else here... | |
1ccb7433 DE |
120 | UInt32 dwBundleType, dwBundleCreator; |
121 | CFBundleGetPackageInfo(cfbApp, &dwBundleType, &dwBundleCreator); | |
1ccb7433 DE |
122 | if(dwBundleType != 'APPL') |
123 | { | |
7db33dd7 SC |
124 | wxLogDebug(wxT("wxMacExecute Not an APPL bundle: %s"), path.c_str()); |
125 | CFRelease(cfbApp); | |
1ccb7433 DE |
126 | CFRelease(cfurlApp); |
127 | return errorCode ; | |
128 | } | |
129 | ||
7db33dd7 SC |
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 | |
1ccb7433 | 135 | { |
7db33dd7 SC |
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 | |
1ccb7433 DE |
145 | for( ; *argv != NULL ; ++argv) |
146 | { | |
7db33dd7 SC |
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; | |
1ccb7433 | 152 | |
7db33dd7 SC |
153 | |
154 | CFURLRef cfurlCurrentFile; // CFURL to hold file path | |
155 | wxFileName argfn(*argv); // Filename for path | |
1ccb7433 | 156 | |
7db33dd7 SC |
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( | |
1ccb7433 | 184 | kCFAllocatorDefault, |
7db33dd7 | 185 | wxMacCFStringHolder(*argv, wxLocale::GetSystemEncoding()), |
1ccb7433 | 186 | NULL); |
7db33dd7 SC |
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 | } | |
1ccb7433 | 197 | |
7db33dd7 SC |
198 | // Add the valid CFURL to the argument array and then |
199 | // release it as the CFArray adds a ref count to it | |
1ccb7433 DE |
200 | CFArrayAppendValue( |
201 | cfaFiles, | |
202 | cfurlCurrentFile | |
203 | ); | |
204 | CFRelease(cfurlCurrentFile); // array has retained it | |
205 | } | |
1ccb7433 | 206 | |
7db33dd7 SC |
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 | |
1ccb7433 DE |
211 | LSLaunchURLSpec launchspec; |
212 | launchspec.appURL = cfurlApp; | |
213 | launchspec.itemURLs = cfaFiles; | |
214 | launchspec.passThruParams = NULL; //AEDesc* | |
7db33dd7 | 215 | launchspec.launchFlags = kLSLaunchDefaults; |
1ccb7433 DE |
216 | launchspec.asyncRefCon = NULL; |
217 | ||
7db33dd7 SC |
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); | |
1ccb7433 | 222 | |
7db33dd7 SC |
223 | // Cleanup corefoundation references |
224 | CFRelease(cfbApp); | |
1ccb7433 DE |
225 | CFRelease(cfurlApp); |
226 | CFRelease(cfaFiles); | |
227 | ||
7db33dd7 | 228 | // Check for error from LSOpenFromURLSpec |
1ccb7433 DE |
229 | if(status != noErr) |
230 | { | |
7db33dd7 SC |
231 | wxLogDebug(wxT("wxMacExecute LSOpenFromURLSpec Error: %d"), |
232 | (int)status); | |
1ccb7433 DE |
233 | return errorCode ; |
234 | } | |
7db33dd7 SC |
235 | |
236 | // No error from LSOpenFromURLSpec, so app was launched | |
237 | return successCode; | |
1ccb7433 DE |
238 | } |
239 |