Game Development Community

Problem launching External Apps while passing arguments

by Gonzo T. Clown · in Torque Game Engine · 02/25/2006 (12:48 pm) · 18 replies

Launching an external app like your safari browser on the Mac is pretty elementary, and launching other apps is pretty straightforward as well. But now, I need the ability to pas parameters to a new App that I'm launching and I'm not having any luck getting it to work.


The following function will build and run with no errors, but it locks Torque up when i try to utilize it...

//  Gonzo - Added at line 2456(macCarbWindow) for launching external apps
bool Platform::openSevenZipper( const char * url )
{
	long len = dStrlen(url);
	
	CFURLRef urls = CFURLCreateFromFileSystemRepresentation ( NULL, url, len, false );
	
	FSRef * appFSRef;
	CFURLGetFSRef(urls, appFSRef);
	
	LSApplicationParameters appParams;
	
	appParams.version = 0;
	appParams.flags = kLSLaunchDontSwitch;
	appParams.application = appFSRef;
	appParams.environment = NULL;
	appParams.argv = NULL;
	appParams.initialEvent = NULL;
	
	LSOpenApplication(&appParams,NULL);
	
	return(true);
}


Does anyone have any ideas what I might be doing wrong here as I am kind of stumped at this point. Any help would be greatly appreciated. FWIW, I managed to get this to function perfectly on a PC(as is most cases), but the Mac is just not being cooperative in this matter.

TIA


Gonzo


EDIT: This is the error the Zcode debugger returns - Unable to disassemble objc_msgSend_rtp

#1
02/25/2006 (5:15 pm)
Gonzo,

I don't have the carbon manuals to fully understand your function at hands. But shuouldn't the appParams.argv contain the URL you want to open ?
#2
02/26/2006 (1:19 pm)
Argv
An array of values of type CFStringRef that specify the arguments that are to be passed to main() in the launched process. The value of this field can be NULL. This field is ignored in Mac OS X v10.4.
#3
02/26/2006 (1:20 pm)
Notice it says it is ignored in OS X v10.4. Mac, the ever confusing operating system. "Think different."
#4
02/26/2006 (1:23 pm)
Want to know why you cant hack a Mac? They give you 1000 potential areas to attack one from, and before you master any of them, they change them all to do something different. Anything you can do on a Mac, you could have done months before on a PC.


Mac's new motto SHOULD be "If it just works, it must be running on a PC"
#5
02/26/2006 (7:50 pm)
I'll pay ANYONE that can answer this question or provide a working solution. Anyone know enough about Macs to make money on them? Now is your chance to pick up some fast cash.
#6
02/26/2006 (10:01 pm)
I can see all the help I WASTED on this community is being returned graciously. This is pathetic. Not even a single GG employee dare risk an answer here?


Pathetic
#7
02/27/2006 (8:22 am)
Quote:I can see all the help I WASTED on this community is being returned graciously. This is pathetic. Not even a single GG employee dare risk an answer here?


Pathetic

Gonzo man, chill. Stomping your feet rarely works. One possibility: You asked your question on the weekend. Second possibility: No one knows.

I don't believe your code is specific to Torque. Have you tried asking around the various OSX mailing lists/forums out on the 'net?

- LightWave Dave
#8
02/27/2006 (10:27 pm)
Third possibility--the post was noted for watch to see if it got answered by the community. If it wasn't, it would have been forwarded to the only Mac developer we have at GG, who is currently swamped with getting 3 different product branches up to speed with universal binary builds.

As David mentioned, take it easy bro. In less than 8 hours I personally had 212 new messages to read, and even had I already forwarded this one (I hadn't), developers don't even look at those emails until they need a break from their primary tasks. They get to them, but it's not immediate.

And as David said, this had nothing whatsoever to do with Torque code, so there is no incentive other than having spare time for a GG dev to answer it in any case. We can whenever we can, but it's not our primary job when the question isn't even related to Torque.

Edit: I hate to sound like I'm coming down on you Gonzo (although I do think your response to the delay was a bit strong)...wasn't meaning to do so much. Just wanted to explain the reasons behind GG's lack of current response to the thread.
#9
02/28/2006 (9:06 am)
You guys are right, I was a bit harsh and impatient, my apologies. I'm just frustrated from what Apple claims as "It's easy to port your code over to the new format for OS X 10.3 and later..." when it's obviously ANYTHING but easy. The Dev docs at Apple leave MUCH to be desired.


Might I graciously point out that while this specific code is not Torque native, it is very likely to be something others will be trying to work out in the future and it would be nice if I or someone else would be able to help them. You said you guys only have one Mac dev at GG so it stands to reason that you guys could use a little more outside help in Mac matters. I would be glad to be as much help as I can in the future but right now I'm feeling pretty helpless, lol.



Quote:Have you tried asking around the various OSX mailing lists/forums out on the 'net?

No, I'm not up to speed on web spots that would be good for these types of questions. I would be very greatful for any links you guys could supply that you feel I could visit for assistance.


Thanks
#10
02/28/2006 (10:42 am)
Gonzo,

One place I look are the mailing lists hosted by apple:

lists.apple.com/mailman/listinfo

I believe the Carbon-dev mailing list archives could be a place to start.

And maybe you've already found it, but here's the link to the Launch Services reference:

developer.apple.com/documentation/Carbon/Reference/LaunchServicesReference/index...

Upon further reading it looks like Launch Services are only available under 10.4, so you'll need a different solution if you want to run under 10.3 and earlier. And that note for the unsupported 'argv' parameter under 10.4 doesn't appear to be something that was taken away but something that hasn't yet been implemented given that this service began with 10.4.

Maybe you can use an Apple Event in the 'initialEvent' parameter to pass what you need to?

Hmm, and a further look it appears that the 10.3 equivalent is LaunchApplication:

developer.apple.com/documentation/Carbon/Reference/Process_Manager/Reference/ref...

Although again it doesn't look like it will pass an argument. Maybe Apple Events are the only way...

- LightWave Dave
#11
02/28/2006 (2:09 pm)
Gonzo:

Tell me a little more about what you're trying to do. I've got 2-3 solutions for ya, depending on what exactly you need this for.
#12
03/01/2006 (8:47 am)
Thank you for the links Dave, I shall dig into them ASAP.


Paul

I want to be able to create zip archives from within Torque using a 3rd party command line program. On the windows platform I can use the standard "CreateProcess" and pass the proper switches(compression commands) and parameters(filepath and name) to the command line app and create the archive with whatever files I need compressed into it. I have the functionality completed and working perfectly on the Win platform, but I cannot get the Mac platform to respond at all. If I run the app(not actually a ".app", it's a UNIX executable. But I could make it into an app if need be) from Terminal, it functions perfectly, but I cannot seem to get it to work from Torque on the Mac when I try to accesss it directly using ICLaunchURL, and in the case of the above function using "LSOpenApplication" I am crashing torque when I try to launch it(might be doing something wrong above).


So in short, I need to be able to send a command with switch parameters and a pathway to the file I want compressed to my archive app from Torque and have it execute the commands(preferably in the background, but not absolutely neccesary).

Any help you can render in this matter would be greatly appreciated. Thanks for your time.


Gonzo
#13
03/01/2006 (2:51 pm)
Ok, so you want to run a command line program from within a mac application.

Open a terminal, type 'man 3 sytem' .
That's basically what you're looking for.

This line of code should do approximately what you want, and this is what I recommend, above the other options listed below, for a quick & dirty implementation.
system("zip -qr common.zip common");

Note that it will block, and torque will hang, until zip is done.
If you need more interactivity, I recommend creating a new Torque thread, and calling system inside the thread, like this:
void zipDemoThread(S32 arg)
{
   system("zip -qr demo.zip demo");
   Con::printf("zip done.");
}

ConsoleFunction( zipDemo, void, 1,1,"")
{
   Thread *t = new Thread((ThreadRunFunction)zipDemoThread,0,true);
}

If you need to listen to the stdout of the program you're calling, you can create a Torque thread just like above, but use popen() instead of system(), and dump the data you read off that pipe to the console. Check the man page on popen for details on using it.

You can also use Cocoa's NSTask object, as a pretty simple way to get some really fancy features.
Objective-C code can be used inside C++ functions, so it's not a huge burden to add Cocoa code to Torque. The objective-c syntax does take some getting used though.
Here's a good discussion, with code snippets, on how to use NSTask : Interacting with the Operating System .

This can all get as complex as you want...
I still recommend just using system(), perhaps in a Torque thread to avoid interface hanging.

Share and Enjoy

/Paul

edit: removed info on a dangerous system call
#14
03/02/2006 (1:22 am)
Paul

I believe NSTask is going to be the best option in this case, but the compiler is barking about parse errors before '[' and NSTask being undeclared(first use of this function) etc...

I've added the Cocoa.frameworks to the frameworks in Xcode but I still get the errors, is there something more I need to do to get it to compile correctly?
#15
03/04/2006 (9:16 am)
Bumpety bump
#16
03/04/2006 (3:13 pm)
Gonzo,

Carbon & Cocoa don't mix just like that. I beleive the best way of doing it would be creating a separate file cocoa file that contains a C wrapper for the NSTask call.
#17
03/13/2006 (9:37 pm)
@Gonzo: Bruno's right. It's more than just sticking some Cocoa code in the middle of your C code, but really not all that much more. Here's a little How-To:

To get Carbon (C++) and Cocoa (Obj-C) to mix, create a new file with a filename like filename.mm.
Put this in that file:
// Adapted from Apple example code found at:
// http://developer.apple.com/documentation/Cocoa/Conceptual/OperatingSystem/Tasks/pipes.html
#import <Cocoa/Cocoa.h>

#include "platform/platform.h"

void testNSTaskProcessData(NSData *inData);

ConsoleFunction( testNSTask, void, 1,1, "")
{   
   NSTask *pipeTask = [[NSTask alloc] init];
   NSPipe *newPipe = [NSPipe pipe];
   NSFileHandle *readHandle = [newPipe fileHandleForReading];
   NSData *inData = nil;
   
   // write handle is closed to this process
   [pipeTask setStandardOutput:newPipe]; 
   [pipeTask setLaunchPath:@"/usr/bin/zip"];
   [pipeTask setArguments:[NSArray arrayWithObjects:@"-h",nil]];
   [pipeTask launch];
   
   while ((inData = [readHandle availableData]) && [inData length])
   {
      testNSTaskProcessData(inData);
   }
   [pipeTask release];
}

void testNSTaskProcessData(NSData *inData)
{
   NSString *string = [[NSString alloc] initWithData:inData encoding:NSASCIIStringEncoding];
   Con::printf(" zip > %s", [string UTF8String]);
}

Ok, if you look at this code, it should be pretty self explanatory. You can mix objective-c and c++ pretty freely, really. You just have to let the compiler know that you want to; you use a special file name to activate the Objective-C++ compiler. Objective-C can be thought of as a really fancy preprocessor + a runtime environment, built on top of C. Since you can mix C and C++, you can mix Objective-C and C++.

Don't forget to include the Cocoa framework in your project, and don't forget to #import .

There are a few esoteric rules about *how* you can mix C++ and Objective-C, read them in this really great guide.

Share and Enjoy.

/Paul
#18
03/14/2006 (8:45 pm)
Paul, thank you so much for the explanation. Once I have a chance to implement your example I'll report back and let you know how things worked out for me. Once again, thank you.

Gonzo