Reputation: 2713
I would like to know how can I open a file with my OS X application, which I wrote in Objective-C. I registered the file types in Info.plist and I have application:openFile:
in my code. I did everything by this post, which was marked as solved.
The problem is that this works only if I drag and drop my file on my application while it is running. But it doesn't work if I just double click on my file. It starts my application, but not as it would start if I would drag and drop. So the code which is in application:openFile:
doesn't run when double-clicked, but only when I drag and drop my file.
EDIT:
Some more detail about my code, and what I am trying to achieve.
I created a wrapper application for an other app. Let's call the other app the "HelperApp.app". This HelperApp is inside the /Contents/
folder of my wrapper app. With the wrapper app I specified a new file type, let's call it ".ha" in the Info.plist file. This file contains some argument commands. What I try to achieve, that when a user clicks on a file which is a ".ha" file, then my wrapper app reads in the argument from this file and sets it for the HelperApp, then starts the HelperApp. This HelperApp is opening different things depending on the argument it gets. Below you can check my code.
I have an AppDelegate.h
and an AppDelegate.mm
by default how the newest Xcode creates it. I added this line to my AppDelegate.h
, just before the "@end":
- (BOOL)processFile:(NSString *)file;
I have these functions in my AppDelegate.mm
:
#import "AppDelegate.h"
#import "ArgumentParser.h"
@implementation AppDelegate
- (void)dealloc
{
[super dealloc];
}
- (BOOL)application:(NSApplication *)WrapperApp openFile:(NSString *)filename
{
return [self processFile:filename];
}
- (BOOL)processFile:(NSString *)file
{
NSLog(@"The following file has been dropped or selected: %@",file);
std::string path = [file cStringUsingEncoding:[NSString defaultCStringEncoding]];
ArgumentParser parser = ArgumentParser();
parser.getArgumentfromFile(path);
parser.setArgumentinFile(); // <== This is the "corrupted" function
NSBundle *mainBundle = [NSBundle mainBundle];
NSString *helperAppPath = [[mainBundle bundlePath]
stringByAppendingString:@"/Contents/HelperApp.app"];
[[NSWorkspace sharedWorkspace] launchApplication:helperAppPath];
return YES;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
}
The corrupted function - setArgumentinFile()
:
void ArgumentParser::setArgumentinFile() {
std::string content = ""; // The file content
std::fstream file;
file.open("HelperApp.app/Contents/Wrapper/HelperApp.app/Contents/Info.plist");
// Open the file and modify the arguments
if(file.is_open()) {
std::stringstream stream;
stream << file.rdbuf();
std::string line = "";
bool isIt = false;
while(getline(stream, line)) {
// This line is the argument list, which needs to be modifyed
if(isIt) {
int index = (int)line.find_last_of("<");
std::string start = line.substr(0, index);
std::string end = line.substr(index, std::string::npos);
std::string argument_list = start + " " + _argument + end;
content += argument_list + '\n';
isIt = false;
}
// Save the rest of the file so we can overwrite it
else {
content += line + '\n';
}
// Next line is the argument list
if(line.find("WineProgramArguments") != std::string::npos) {
isIt = true;
}
}
file.flush();
file.close();
}
else {
file.flush();
file.close();
throw std::runtime_error("File isn't opened");
}
file.open("HelperApp.app/Contents/Wrapper/HelperApp.app/Contents/Info.plist", std::ios::out);
// Open the file and overwrite it with the modifyed argument
if(file.is_open()) {
file << content;
file.flush();
file.close();
}
else {
file.flush();
file.close();
throw std::runtime_error("File isn't opened");
}
}
If I comment out the above function from the processFile
function in AppDelegate
, then everything works "smoothly". I mean the wrapper app starts and it starts the HelperApp with default arguments. So here should be the error...
Upvotes: 5
Views: 4174
Reputation: 802
right-click vs. double-click to open a file behave differently!
Apple Docs:
If the user started up the application by double-clicking a file, the delegate receives the application:openFile: message before receiving applicationDidFinishLaunching:. (applicationWillFinishLaunching: is sent before application:openFile:.)
The Apple Docs leave out a vital piece of info... I had assumed that a right-click -> 'Open With' operation in Finder would be the same as a double-click. Its NOT!
application:openFile: happens AFTER applicationDidFinishLaunching: in this case!
Was scratching my head for an hour on this one.
Upvotes: 1
Reputation: 2713
The problem was, that I gave the wrong path in my function. This path worked if I started the app from Xcode, but did not if I started the app by itself.
Here is the post which solved my problem!
Upvotes: 1
Reputation: 6707
I've figured it out. When you double-click on a file icon, the application will launch itself, other things done correctly. But the application that responds to your action is not necessarily the one that you built for the last time. Probably, an old copy of your application is responding. Take a look at Library > Developer > Xcode > DrivedData. You should see many folders for your application. You can locate your application folders by right-clicking and choosing Shown In Finder after build one. Trash them all, and build a new application. Then double-click and see what happens now.
Upvotes: 1
Reputation: 124997
If you've implemented -application:openFile:
, it should be called when you double-click a file of the type that you've registered. You say that the app launches, so the OS is trying to use your app to open the file. Here's a useful note from the documentation:
If the user started up the application by double-clicking a file, the delegate receives the application:openFile: message before receiving applicationDidFinishLaunching:. (applicationWillFinishLaunching: is sent before application:openFile:.)
So, if you're doing anything in -applicationDidFinishLaunching:
that has to be done before you open any files, that could be your problem. Consider moving your app initialization code to -applicationWillFinishLaunching:
.
Upvotes: 4