Unable to see/open files from Mac

First endeavor at Mac development. My app is a baseball game that uses several folders to contain the database and results files for each of the seasons. It also has different folders for graphics and sound files that can be customized by the user. As a result there are several folders and potentially lots of files within the folders. It’s been running on Windows for several years but I made the move to Xojo so that I can also offer it on the Mac. With that I am converting the database from MS Access to SQLite although I don’t think that is really relevant to my issue other than providing background to this conversation.

The aforementioned folders are stored in the Documents folder of the user. This has always worked fine for me in Windows, including with my move to Xojo. I am trying to do the same on the Mac but I can’t seem to get past the folderitem.exists being false with a LastErrorCode of 101. I am trying to use the same folder hierarchy as Windows and have tried it both within the Mac Documents folder and also the folder of the application (which for now is actually the project folder for the program).

I have tried both the SpecialFolder.Documents method and also SpecialFolder.CurrentWorkingDirectory, then appending the remaining path name to the results of SpecialFolder, my latest (but unsuccessful) attempt below. When I try to find a specific file using one of the paths below (appending the file name to those strings) is where I keep getting the file not found. I am using GetFolderItem with one of the paths below, with no other parameters used for this method besides the string containing the path.

'set path to user documents
#if TargetWin32
dp = SpecialFolder.Documents
app.UserDocsPath = dp.NativePath
#else
dp = SpecialFolder.CurrentWorkingDirectory 'results of dp = “/”
app.UserDocsPath = dp.NativePath
#Endif

#if TargetMacOS
app.CommonPath = app.UserDocsPath + “Data/Common/”
app.SeasonsPath = app.UserDocsPath + “Data\Seasons/”
app.HelpPath = app.UserDocsPath + “Help/”
app.BallparkImagePath = app.UserDocsPath + “Ballpark Images/”
app.PlayerImagePath = app.UserDocsPath + “Player Images/”
app.TeamImagePath = app.UserDocsPath + “Team Images/”
app.SoundFilesPath = app.UserDocsPath + “Sound Files/”
#else
app.CommonPath = app.UserDocsPath + “Dombrov Baseball Sim\Data\Common”
app.SeasonsPath = app.UserDocsPath + “Dombrov Baseball Sim\Data\Seasons”
app.HelpPath = app.UserDocsPath + “Dombrov Baseball Sim\Help”
app.BallparkImagePath = app.UserDocsPath + “Dombrov Baseball Sim\Ballpark Images”
app.PlayerImagePath = app.UserDocsPath + “Dombrov Baseball Sim\Player Images”
app.TeamImagePath = app.UserDocsPath + “Dombrov Baseball Sim\Team Images”
app.SoundFilesPath = app.UserDocsPath + “Dombrov Baseball Sim\Sound Files”
#endif

'verify that Dombrov Baseball Sim Common database is present
cp = App.CommonPath + “DombrovCommon.db3”

f = GetFolderItem(cp) 'FolderItem for Dombrov Baseball Sim Common database

'f is getting set as a folderitem but f.exists = false

Sorry for being so verbose but I thought the background might help. I have a feeling I am missing something that is going to make me feel silly when I find it but meanwhile thought I’d try posting this and hopefully get a suggestion or two.

Thanks,

Richard

One more piece of info … if I copy the file into the same folder as where my project is then it finds it just fine. Is this a Mac permissions issue?

cp = “DombrovCommon.db3”
f = GetFolderItem(cp) 'FolderItem for Dombrov Baseball Sim Common database

#if TargetMacOS
app.CommonPath = app.UserDocsPath + “Data/Common/”
app.SeasonsPath = app.UserDocsPath + “Data\Seasons/

“Data\Seasons/” should be “Data/Seasons/”

Thanks Axel, I also noticed that but I am still getting same results.

I would recommend using FolderItems directly instead of using the path and trying to recreate the FolderItem.

Thanks Tim, but I’m not sure that I understand what that means. I am using Special Folder to get the Documents path, but I also need to append one or more folders plus a file name to whatever gets returned by SpecialFolder.

You can use Folderitem.Child to navigate down the folder item path specifying the name of each successive folder and finally the file itself instead of creating the path as a string and then trying to obtain a folder item from that path.
i.e.

dp = SpecialFolder.CurrentWorkingDirectory 'results of dp = "/" app.UserDocsPath = dp.NativePath app.CommonPath = app.UserDocsPath + "Data/Common/" cp = App.CommonPath + "DombrovCommon.db3" f=GetFolderItem(cp)
Can be done as:

f=SpecialFolder.CurrentWorkingDirectory.Child("Data").Child("Common").Child("DombrovCommon.db3")

FolderItem has a Child function which operates in a cross platform way. Keep your reference to app.UserDocsPath as a folderitem instead of a string. Eg.,

#if TargetWin32
dp = SpecialFolder.Documents
app.UserDocs = dp
#else
dp = SpecialFolder.CurrentWorkingDirectory
app.UserDocs = dp
#Endif

Then use Child to traverse the path.

#if TargetMacOS
app.CommonFolder = app.UserDocs.Child("Data").Child("Common")
#else
app.CommonFolder = app.UserDocs.Child("Dombrov Baseball Sim").Child("Common")
#endif
...
cp = app.CommonFolder.Child("DombrovCommon.db3")

Excellent advise gentlemen, that indeed worked. Fortunately I don’t have that many places in the code where I am doing this so it should be easy to change those instances. And I assume this will work fine from Windows so I won’t even need to have the compiler directives and separate code for that.

Thanks very much - greatly appreciated. I’m still a relative newbie to Xojo (less than a year) but I’ve found this forum to be outstanding with lots of people willing to share their knowledge, which in turn has helped me to learn a lot. Night and day difference compared to my previous IDE. :slight_smile:

Richard

Richard:

It may be a stupid advice, but when I read: “ Fortunately I don’t have that many places in the code where I am doing this” I think I have to tell this:

you seems to have a finite number of folders with data. Why don’t you use a set of global properties that you initialize in App at the application launch (and check for the presence of these folders) ?
Then, you only have to use the global property for sounds as:

MySoundFI = gSoundsFR.Child(“Goooooaaaal.mp3”)
If MySoundFI = Nil Or Not MySoundFI.Exists Then // Check if that sound is in the Sounds folder

Of course, I assume you have MP3 sounds in a folder called “Sounds”…

Hello Emile,

I think that is excellent advice and is exactly what I am doing. It is a small investment for me to go back and change this in a few places (it’s about a dozen) but it is actually easier and more straightforward than what I was doing before. Not sure why I wasn’t using the FolderItem Child property but I am now,

Thanks,

Richard

Richard, are you thinking to distribute this application via the Mac App Store?

If you are thinking to do that, you’re going to have to change the way your application works to be consistent with Apple’s guidelines. I’m just letting you know in case this is somewhere you are heading.

First things first, Mac Apps are self contained, so they (generally) can be placed wherever and still open. Secondly you won’t be able to read or write to the users documents folder (without permission).

Most of these files seem like resources ( graphics, sounds and game data ), so they need to be stored within the “Resources” folder of the application bundle. Don’t put any files that you need to write to in the “Resources” folder, as this is read only.

  • Xojo can auto copy the data into the bundle for you, with a “Copy Files” script step.
  • a bit of code will then help you to get at the files in the Resources folder.
app.executableFile.parent.parent.child( "Resources" )

If you want to store saved games and other data without first asking the user where they want to store it, you’ll need to store it in what’s known as the “Application Support” folder.

  • Check specialFolder.applicationData then create a subfolder with the name of your application or bundle identifier.

I’ve started to see this quite frequently with developers used to the freedom of Windows, want to release an app on the Mac App Store. Apple really do want it done their way.

Thanks very much Sam, that is some great advise. Eventually I would like to pursue the Apple store so it would be good to have it ready setup to meet standards in the first place. I’m definitely not obligated to using the Documents folder and it is a fairly easy change at the beginning of the program to use something else. My preference is to not ask the user where to store data so SpecialFolder.ApplicationData would be fine. (and I should be able to do that from Windows too).

This raises a good point about bundling for the Mac. On Windows I am using InnoSetup and the user can install everything, the program, graphics, sounds, data, from one setup run. They can also install them individually if desired, and actually it is common to update only of those components. I haven’t honestly looked at how this is going to work on the Mac, I wish there was an Innosetup for Mac because that sure makes it easy. But I was thinking that I may need to write something like you mentioned if necessary. The individual graphics and sounds files are read-only but everything else is read-write. Plus the user can add or remove from the graphics and sound files so effectively that makes them read-write as well.

I like the concept of the self-contained app but am still coming to grasps with how that will work with my app. This is part of my decision to make my app available to the Mac market and I was expecting a learning curve.

Thanks again - this has been a very helpful thread for me.

Richard

Simply copy all your files to SpecialFolder.ApplicationData.Child(“yourspace”) the first time you run the program and this is the same as a work directory under Windows. It may not be Innosetup, but it is fairly easy to create your own data structure there.
For scratch work, I also use SpecialFolder.Temporary which is convenient if you do not need to keep the file for future use. It works for the Apple Store as well.

Richard,
I hope it helps, there is a lot to learn when doing OS X development and the App Store, adds an extra layer of steps. I do see that people struggle more when they’re used to Windows as Apple’s system really requires extra work on things like file handling.

On the flip side, once you get in developing OS X applications, Apple’s toolbox contains far more functionality than Windows and the stuff you’ll then be able to do on the Mac that requires soooo much more work on Windows.

It’s 6 of one, and half a dozen of the other :slight_smile:

There’s plenty of OS X devs here who can help you out with OS X stuff.

As for Inno Setup, Apple do have their own installer for apps, however it’s only really used when selling via the Mac App Store (and you still need to make your application self contained) or if you’re building drivers or other things that must be installed in the correct place. Michel’s advice is great for creating a ‘self-contained’ app that can install it’s components.

Modifying files in the application bundle, (allowing the user to customize sounds and graphics) will break the application code signature and then it won’t be able to function any more (this is one of Apple’s security functions that reduces the likelihood of viruses spreading through applications).