Howto register file extensions and open the files
Posted: Wed Sep 17, 2008 4:26 pm
If you want to do one of these things with PB for OSX, then this post is for you:
- associate file extensions to open with your app on doubleclick
- associate an icon with your file extension
- allow files to be opened by draging them to your app icon
Step 1: code
Unlike on other OS, the files to open are not passed on the commandline but through events after the program has launched. This results in more code to catch these events than reading the commanline, but the positive point is that this way you receive a file event even when the user drags/doubleclicks a file after he started your program.
Here is the code to catch the event and extract the filenames:
If you run this, you will notice that you cannot drag any files to the application. That is because you need to tell finder what types of files you accept. This leads us to the next step...
Step 2: configuration
To tell finder about your file types, edit the "Info.plist" in your bundle directory.
- Compile the above code to a .app
- Select the .app in finder.
- Open the context-menu and select "Show package contents" (this will display the contents of the .app directory)
- Open the Info.plist file in the Contents folder as described below.
Note: The compiler overwrites this file on every compilation, so better save your modifications elsewhere and copy the file back after every new compilation. (You can also automate this by creating a small tool that is run after the executable is created)
Keep in mind that if you make some changes in the compiler options, you have to apply the resulting changes in the generated file also to your saved copy. (mainly the CFBundleExecutable and CFBundleIconFile keys)
Note2: The changes you make to the file may not immediately be seen by the finder. Especially if you previously executed the program with different settings. It sometimes helps to create the .app in a new location or copying the .app to a different folder for finder to notice the changes. In some cases only a restart will make the changes take effect. (happened to me with setting an icon for the files)
An example first:
This is what we add to the Info.plist for the IDE (it goes into the main <dict> tag)
Another example:
Use this if you just want any file to be dragable to your application icon, but no specific filetype to be registered:
- As you can see you can have multiple extensions in the CFBundleTypeExtensions array
- You can also have multiple versions of the entre <dict> part, to associate different extensions with different icons for example
- You need to specify atleast the CFBundleTypeExtensions and CFBundleTypeRole parts, the rest is optional
Here is a short description of the fields:
CFBundleTypeExtensions (required)
Specifies the list of file extensions. The <array> is needed, even if there is only on extension.
To make this setting apply for all types (for example if you want any file to be droppable to your app icon), use a "*".
CFBundleTypeIconFile
Here you can set an icon file for these file extensions. The icon must be copied to the Contents/Resources folder of the .app
CFBundleTypeName
Set a name to describe your file type here.
CFBundleTypeRole (required)
Specify what your application does with the type. Values can be "Editor", "Viewer", "Shell" or "None".
All available keys for the Info.plist are explained in detail here:
http://developer.apple.com/documentatio ... tKeys.html
There are some other keys that may be of intrest to you, like the CFBundleGetInfoString one, which allows to set a string that can be seen when the user selects "Get Info" for your .app.
- associate file extensions to open with your app on doubleclick
- associate an icon with your file extension
- allow files to be opened by draging them to your app icon
Step 1: code
Unlike on other OS, the files to open are not passed on the commandline but through events after the program has launched. This results in more code to catch these events than reading the commanline, but the positive point is that this way you receive a file event even when the user drags/doubleclicks a file after he started your program.
Here is the code to catch the event and extract the filenames:
Code: Select all
;
; Receive the OpenDocument event on OSX
;
; Some required definitions
;
#eventNotHandledErr = -9874
#CoreEventClass = 'aevt'
#AEOpenDocuments = 'odoc'
#typeFSS = 'fss '
#typeAEList = 'list'
#typeFSRef = 'fsrf'
#keyDirectObject = '----'
#typeNull = 'null'
#noErr = 0
Structure FSRef
hidden.b[80]
EndStructure
Structure AEDesc
desctiptorType.l
dataHandle.l
EndStructure
; ProcedureCDLL is important, for the right calling convention (on x86) and
; the correct callback behavior (therefore the DLL part)
;
ProcedureCDLL OpenDocument(*appleEvt, *reply, refcon)
; extract the event parameters
If AECreateDesc_(#typeNull, 0, 0, @documents.AEDesc) = #noErr
If AEGetParamDesc_(*appleEvt, #keyDirectObject, #typeAEList, @documents) = #noErr
If AECountItems_(@documents, @n) = 0
*Buffer = AllocateMemory(1000)
If *Buffer
; There can be multiple files sent
For i = 1 To n
If AEGetNthPtr_(@documents, i, #typeFSRef, @keyWd, @typeCd, @fileRef.FSRef, SizeOf(FSRef), @actualSize) = #noErr
If FSRefMakePath_(@fileRef, *Buffer, 1000) = #noErr
File$ = PeekS(*Buffer, -1, #PB_Ascii)
;
; If you want to accepte directories too, then change this
;
If FileSize(File$) >= 0
;
; Here you have the filename to open
;
AddGadgetItem(0, -1, File$)
EndIf
EndIf
EndIf
Next i
FreeMemory(*Buffer)
EndIf
EndIf
EndIf
AEDisposeDesc_(@documents)
EndIf
EndProcedure
If OpenWindow(0, 0, 0, 600, 300, "Open Document test", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)
ListViewGadget(0, 10, 10, 580, 280)
; Call this before processing the first window events, else you may miss the open event!
;
If AEInstallEventHandler_(#CoreEventClass, #AEOpenDocuments, @OpenDocument(), 0, 0) <> #NoErr
AddGadgetItem(0, -1, "cannot install event handler!")
EndIf
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
End
Step 2: configuration
To tell finder about your file types, edit the "Info.plist" in your bundle directory.
- Compile the above code to a .app
- Select the .app in finder.
- Open the context-menu and select "Show package contents" (this will display the contents of the .app directory)
- Open the Info.plist file in the Contents folder as described below.
Note: The compiler overwrites this file on every compilation, so better save your modifications elsewhere and copy the file back after every new compilation. (You can also automate this by creating a small tool that is run after the executable is created)
Keep in mind that if you make some changes in the compiler options, you have to apply the resulting changes in the generated file also to your saved copy. (mainly the CFBundleExecutable and CFBundleIconFile keys)
Note2: The changes you make to the file may not immediately be seen by the finder. Especially if you previously executed the program with different settings. It sometimes helps to create the .app in a new location or copying the .app to a different folder for finder to notice the changes. In some cases only a restart will make the changes take effect. (happened to me with setting an icon for the files)
An example first:
This is what we add to the Info.plist for the IDE (it goes into the main <dict> tag)
Code: Select all
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>pb</string>
<string>pbi</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>FileIcon.icns</string>
<key>CFBundleTypeName</key>
<string>PureBasic Sourcecode</string>
<key>CFBundleTypeRole</key>
<string>Editor</string>
</dict>
</array>
Use this if you just want any file to be dragable to your application icon, but no specific filetype to be registered:
Code: Select all
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>*</string>
</array>
<key>CFBundleTypeRole</key>
<string>Editor</string>
</dict>
</array>
- You can also have multiple versions of the entre <dict> part, to associate different extensions with different icons for example
- You need to specify atleast the CFBundleTypeExtensions and CFBundleTypeRole parts, the rest is optional
Here is a short description of the fields:
CFBundleTypeExtensions (required)
Specifies the list of file extensions. The <array> is needed, even if there is only on extension.
To make this setting apply for all types (for example if you want any file to be droppable to your app icon), use a "*".
CFBundleTypeIconFile
Here you can set an icon file for these file extensions. The icon must be copied to the Contents/Resources folder of the .app
CFBundleTypeName
Set a name to describe your file type here.
CFBundleTypeRole (required)
Specify what your application does with the type. Values can be "Editor", "Viewer", "Shell" or "None".
All available keys for the Info.plist are explained in detail here:
http://developer.apple.com/documentatio ... tKeys.html
There are some other keys that may be of intrest to you, like the CFBundleGetInfoString one, which allows to set a string that can be seen when the user selects "Get Info" for your .app.