Results 1 to 10 of 10

Thread: Distributing Program with its own File Structure in MacOS Application Bundle

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Okay. The path thing is working. My game crashes because of another reason.

    All music and sound effects are played using an external commandline mp3 player (mpg123). This has several advantages, so I want to keep this.

    mpg123 is invoked by using a TProcess which I named "ExtProgram". Here's the code where it crashes ONLY when I start the game from the app bundle (it always works when started from command line!)

    Code:
    procedure PlayMusic(SoundFile: string);
    begin
      StopMusic;
      if blUseExternPlayer = True then
      begin
        ExtProgram.CommandLine := strExternPlayer + ' "' + CONST_DATADIR + 'music/' + Soundfile + '"';
    
        ExtProgram.Execute;
      end;
    end;
    I already have printed the complete ExtProgram.CommandLine in a debug file, to ensure that the path is correct -- it is. But still, the program crashes at the ExtProgram.Execute part.

    Why, and why only when started as App bundle? Aren't apps allowed to run other programs?


    Edit: A bit closer. Usually, I only passed the name of the extern binary (mpg123) to TProcess. Then the game crashed. When I passed the full path to the binary (i.e. /usr/local/bin/mpg123), the game did not crash -- but obviously mpg123 wasn't running either (because I didn't hear anything), although now both the paths to the binary and to the music file to play were full and correct.

    (By the way, I noticed that many examples in the www use TUTF8Process instead TProcess, and they also use a function "FindDefaultExecutablePath" to get the full path of a unix application on a system, but neither TUTF8Process nor FileUtil (where FindDefaultExecutablePath would be included) seem to be available on Mac).
    Last edited by Mario Donick; 10-01-2011 at 07:53 AM.

  2. #2
    But: Why is MacOS so complicated here? Why does a simple reference to the Resources folder with "../Resources" not work from inside the "MacOS" folder? Are these security reasons?
    "../Resources" is a path relative to the current directory of your running process. I don't know what is the current directory when the program is started by clicking on a bundle.app, I don't know if anything is guaranteed here. (Try printing GetCurrentDir to your log to experiment). Most likely it's not something you expect, and this causes your troubles...

    Why, and why only when started as App bundle? Aren't apps allowed to run other programs?
    I can't help with this one. It's certainly possible to run another program. A program started by clicking on a bundle runs as a "normal" program, without any additional security restrictions, *as far as I know*.

    You can always run a bundle from a terminal, like "open xxx.app". This should work exactly like clicking from Finder. Maybe something helpful will be printed to stderr then.


    (By the way, I noticed that many examples in the www use TUTF8Process instead TProcess, and they also use a function "FindDefaultExecutablePath" to get the full path of a unix application on a system, but neither TUTF8Process nor FileUtil (where FindDefaultExecutablePath would be included) seem to be available on Mac).
    TUTF8Process is inside UTF8Process unit. Both this and FileUtil should be available just fine on Mac OS X. Remember that they are part of Lazarus library (LCL), not built-in FPC units. So add to your Lazarus project file dependency on lcl package (or add relevant paths to your ~/.fpc.cfg if you use FPC from the command-line).

    In any case, these are most probably not related to your problems, so I wouldn't worry about them now. TUTF8Process is just a version of TProcess that treats all the strings as UTF-8.

  3. #3
    There is no reason to get confused by the application bundle. Just make sure that you set the current directory and you will be fine. You do that like this:

    procedure Home;
    var
    mainBundle: CFBundleRef;
    resourcesURL: CFURLRef;
    path: AnsiString;
    success: Boolean;
    begin
    mainBundle := CFBundleGetMainBundle();
    resourcesURL := CFBundleCopyResourcesDirectoryURL(mainBundle);
    SetLength(path, PATH_MAX);
    success := CFURLGetFileSystemRepresentation(resourcesURL, TRUE, PChar(path), PATH_MAX);
    CFRelease(resourcesURL);
    if success then
    chdir(path);
    end;

    This makes the Resources folder your current directory.

  4. #4
    Quote Originally Posted by Mario Donick View Post
    All music and sound effects are played using an external commandline mp3 player (mpg123). This has several advantages, so I want to keep this.

    mpg123 is invoked by using a TProcess which I named "ExtProgram". Here's the code where it crashes ONLY when I start the game from the app bundle (it always works when started from command line!)

    Code:
    procedure PlayMusic(SoundFile: string);
    begin
      StopMusic;
      if blUseExternPlayer = True then
      begin
        ExtProgram.CommandLine := strExternPlayer + ' "' + CONST_DATADIR + 'music/' + Soundfile + '"';
    
        ExtProgram.Execute;
      end;
    end;
    I already have printed the complete ExtProgram.CommandLine in a debug file, to ensure that the path is correct -- it is. But still, the program crashes at the ExtProgram.Execute part.

    Why, and why only when started as App bundle? Aren't apps allowed to run other programs?


    Edit: A bit closer. Usually, I only passed the name of the extern binary (mpg123) to TProcess. Then the game crashed. When I passed the full path to the binary (i.e. /usr/local/bin/mpg123), the game did not crash -- but obviously mpg123 wasn't running either (because I didn't hear anything), although now both the paths to the binary and to the music file to play were full and correct.
    You are certainly allowed to run other programs. I do it all the time. However, I never use TProcess, at least not if I need to pass data between the two processes. In such cases i use ptyfork. In other cases I can use fork and exec just like TProcess does.

    As you say, with a full path things get more stable. Isn't it the current directory that needs to be known again? And a proper call to chdir would help?

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •