source: trunk/Cocoa/F-Script Anywhere/Source/DeVercruesseProcess.m@ 229

Last change on this file since 229 was 222, checked in by rchin, 18 years ago

Fixed problem with F-Script leaking file handles (caused F-Script to not be able to inject into applications after a certain number of running apps had been launched). The problem was in appIsPEF calling open(2) but not close(2) before returning.

File size: 8.5 KB
Line 
1//
2// DeVercruesseProcess.m
3//
4// Created by Frank Vercruesse on Wed Apr 04 2001.
5// Copyright (c) 2001 Frank Vercruesse.
6//
7//
8// This program is free software; you can redistribute it and/or
9// modify it under the terms of the GNU General Public License
10// as published by the Free Software Foundation; either version 2
11// of the License, or (at your option) any later version.
12//
13// This program is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16// GNU General Public License for more details.
17//
18// You should have received a copy of the GNU General Public License
19// along with this program; if not, write to the Free Software
20// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21// 02111-1307, USA.
22
23#import "DeVercruesseProcess.h"
24#import "DeVercruesseProcessManager.h"
25
26
27@implementation DeVercruesseProcess
28
29+ (id)processWithPSN:(ProcessSerialNumber*)sn
30{
31 return [[[self alloc] initWithPSN:sn] autorelease];
32}
33
34- (id)init
35{
36 return [self initWithPSN:nil];
37}
38
39- (id)initWithPSN:(ProcessSerialNumber*)sn
40{
41 OSErr err;
42 CPSProcessInfoRec pInfo;
43 int dummy;
44
45
46 if( sn )
47 {
48 err = CPSGetProcessInfo( (CPSProcessSerNum*) sn, &pInfo, nil, 0, &dummy, nil, 0);
49
50 if( !err )
51 {
52 self = [super init];
53
54 if( self )
55 {
56 psn.highLongOfPSN = sn->highLongOfPSN;
57 psn.lowLongOfPSN = sn->lowLongOfPSN;
58
59 pid = pInfo.UnixPID;
60 flavour = pInfo.Flavour;
61 attributes = pInfo.Attributes;
62 type = pInfo.ExecFileType;
63 creator = pInfo.ExecFileCreator;
64
65 bundleIdentifier = nil;
66 identifier = nil;
67
68 name = nil;
69 loc = nil;
70 img = nil;
71 }
72 }
73 else
74 {
75 [self dealloc];
76 return nil;
77 }
78 }
79 else
80 {
81 [self dealloc];
82 return nil;
83 }
84
85 return self;
86}
87
88- (void)dealloc
89{
90 [bundleIdentifier release];
91 [identifier release];
92 [name release];
93 [img release];
94 [cachedImage release];
95 [loc release];
96
97 [super dealloc];
98}
99
100- (NSString *)executableLoc;
101{
102 CFStringRef bundleLoc = (CFStringRef) [self loc];
103 CFURLRef bundleURL;
104 CFBundleRef bundleRef;
105
106 if (bundleLoc == NULL) {
107 // GetProcessBundleLocation returns NULL on 10.1.5 for certain CFM Carbon applications (BBEdit 6.5.3) - njr
108 return nil; // XXX should really handle this better, but for the purposes of F-Script Anywhere, we donÕt care if itÕs not a Carbon app, and this works fine going forward.
109 }
110
111 bundleURL = CFURLCreateWithFileSystemPath(NULL, bundleLoc, kCFURLPOSIXPathStyle, NO);
112 bundleRef = CFBundleCreate(NULL, bundleURL);
113 CFRelease(bundleURL);
114
115 if (bundleRef == NULL) {
116 BOOL isDir;
117 if ([[NSFileManager defaultManager] fileExistsAtPath: [self loc] isDirectory: &isDir] && !isDir)
118 return [self loc];
119 return nil; // not a bundle or file
120 } else {
121 CFURLRef execURL = CFBundleCopyExecutableURL(bundleRef);
122 CFURLRef absURL = CFURLCopyAbsoluteURL(execURL);
123 CFStringRef execPath = CFURLCopyFileSystemPath(absURL, kCFURLPOSIXPathStyle);
124
125 if (absURL != NULL) CFRelease(absURL);
126 if (execURL != NULL) CFRelease(execURL);
127 CFRelease(bundleRef);
128 return [(NSString *)execPath autorelease];
129 }
130}
131
132
133- (NSString*)loc
134{
135 char buffer[1025];
136 FSRef location;
137
138
139 if( !loc )
140 {
141 if( !GetProcessBundleLocation( &psn, &location) )
142 {
143 FSRefMakePath( &location, buffer, 1024);
144 loc = [NSString stringWithUTF8String:buffer];
145 [loc retain];
146 }
147 }
148
149 return loc;
150}
151
152- (NSString*)name;
153{
154 char buffer[1025];
155 CFStringRef pName;
156
157
158 if( !name )
159 {
160 if( !name && (CopyProcessName( &psn, &pName) == noErr) ) // with thanks to Dylan Ashe
161 {
162 CFStringGetCString( pName, buffer, 256, CFStringConvertNSStringEncodingToEncoding( [NSString defaultCStringEncoding]));
163
164 name = [NSString stringWithCString:buffer];
165 [name retain];
166
167 CFRelease( pName);
168 }
169 // CFBundleName code demoted to alternate method because it was causing plist processing issues in Jaguar, yet CopyProcessName doesn't work for everything, e.g. Help Viewer - njr
170 else if( [self loc] )
171 {
172 NSBundle *b = [NSBundle bundleWithPath:loc];
173 if( b )
174 {
175 name = [b localizedStringForKey:@"CFBundleName" value:@"_AsM_nO_nAmE_" table:@"InfoPlist"];
176
177 if( [name isEqualToString:@"_AsM_nO_nAmE_"] )
178 name = [[b infoDictionary] objectForKey:@"CFBundleName"];
179
180 if( name )
181 [name retain];
182 }
183 }
184
185 }
186
187 return name ? name : NSLocalizedString(@"<<unknown application>>", "Name used when application name cannot be determined");
188}
189
190- (NSImage*)img
191{
192 if( !img )
193 {
194 if( [self loc] )
195 {
196 img = [[NSWorkspace sharedWorkspace] iconForFile:loc];
197
198 if( img )
199 {
200 [img setDataRetained:YES];
201// [img setCachedSeparately:YES]; // added 8/26/01 by Frank
202 [img retain];
203 }
204 }
205 }
206
207 return img;
208}
209
210- (NSImage *)cachedImage;
211{
212 return cachedImage;
213}
214
215- (void)setCachedImage:(NSImage *)anImage;
216{
217 if (anImage != cachedImage) {
218 [anImage retain];
219 [cachedImage release];
220 cachedImage = anImage;
221 }
222}
223
224
225- (ProcessSerialNumber*)psn
226{
227 return &psn;
228}
229
230- (UInt32)pid
231{
232 return pid;
233}
234
235- (UInt32)flavour
236{
237 return flavour;
238}
239
240- (UInt32)attributes
241{
242 CPSProcessInfoRec pInfo;
243 int dummy;
244
245
246 if( CPSGetProcessInfo( (CPSProcessSerNum*) &psn, &pInfo, nil, 0, &dummy, nil, 0) == noErr )
247 attributes = pInfo.Attributes;
248
249 return attributes;
250}
251
252- (UInt32)type
253{
254 return type;
255}
256
257- (UInt32)creator
258{
259 return creator;
260}
261
262- (NSString*)identifier
263{
264 if( !identifier )
265 {
266 identifier = [[NSString alloc] initWithFormat:@"%@%.8X%.8X",
267 [self bundleIdentifier], [self type] ? type : 'APPL', [self creator] ? creator : '\?\?\?\?'];
268 }
269
270 return identifier;
271}
272
273- (NSString*)bundleIdentifier
274{
275 NSBundle *b;
276
277
278 if( !bundleIdentifier && [self loc] && (b = [NSBundle bundleWithPath:loc]) )
279 bundleIdentifier = [[b bundleIdentifier] retain];
280
281 return bundleIdentifier ? bundleIdentifier : @"";
282}
283
284
285- (unsigned)hash
286{
287 return psn.lowLongOfPSN;
288// return pid;
289}
290
291- (BOOL)isEqual:(id)anObject
292{
293 if( anObject )
294 return CPSEqualProcess( (CPSProcessSerNum*) &psn, (CPSProcessSerNum*) [anObject psn]);
295 else
296 return NO;
297}
298
299- (BOOL)isEqualToCurrent
300{
301 return [self isEqual:[ProcessMgr currentProcess]];
302}
303
304- (BOOL)isEqualToFront
305{
306 return [self isEqual:[ProcessMgr frontProcess]];
307}
308
309- (BOOL)isStillRunning
310{
311 CPSProcessInfoRec pInfo;
312 int dummy;
313
314
315 if( CPSGetProcessInfo( (CPSProcessSerNum*) &psn, &pInfo, nil, 0, &dummy, nil, 0) == noErr )
316 return YES;
317 else
318 return NO;
319}
320
321- (BOOL)isBackgroundOnly
322{
323 return (((attributes & kCPSBGOnlyAttr) | (attributes & kCPSUIElementAttr)) != 0);
324}
325
326- (BOOL)isHidden
327{
328 return (([self attributes] & kCPSHiddenAttr) != 0);
329}
330
331
332- (BOOL)isClassic
333{
334 return (flavour == kCPSBlueApp);
335}
336
337- (BOOL)isCarbon
338{
339 return (flavour == kCPSCarbonApp);
340}
341
342- (BOOL)isCocoa
343{
344 return (flavour == kCPSYellowApp);
345}
346
347
348- (void)show
349{
350 if( [self isStillRunning] )
351 CPSPostShowReq( (CPSProcessSerNum*) &psn);
352}
353
354- (void)hide
355{
356 if( [self isStillRunning] )
357 CPSPostHideReq( (CPSProcessSerNum*) &psn);
358}
359
360- (void)makeFront
361{
362 if( [self isStillRunning] )
363 {
364 CPSSetFrontProcess( (CPSProcessSerNum*) &psn);
365 CPSPostShowReq( (CPSProcessSerNum*) &psn);
366 }
367}
368
369- (void)kill
370{
371 [self kill:NO];
372}
373
374- (void)kill:(BOOL)hard
375{
376 if( [self isStillRunning] )
377 CPSPostKillRequest( (CPSProcessSerNum*) &psn, hard ? bfCPSKillHard : 0 );
378}
379
380- (NSString *)description;
381{
382 return [NSString stringWithFormat: @"%@ pid %d: '%@' (%@)", [super description], [self pid], [self name], [self identifier]];
383}
384
385@end
Note: See TracBrowser for help on using the repository browser.