How is "Open with" on macOS populated internally? - macos

I know I can associate my application with a certain extension by editing the Info.plist file in my app bundle:
...
<key>CFBundleTypeExtensions</key>
<array>
<string>myext</string>
</array>
While this works, my "Open with" list gets littered with duplicate entries of the different versions of the application I'm developing on that machine. There are even entries for really old versions that I've never opened on that very computer! (It's a new machine being synced with Dropbox so there are older releases in my file system.)
It seems as macOS would scan for app bundles even outside of /Application and adds all applications it finds to "Open with". A workaround is to reset the "Open with" list with this command I found somewhere here on SO I think:
/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -kill -r -domain local -domain user;killall Finder
How is the "Open with" list populated internally? Is macOS really scanning my drive looking for Info.plist files with CFBundleTypeExtensions entries? And is there any way to avoid having my "Open with" list littered with older versions other then deleting (or zipping) them?
NB: I'm not using Xcode but build my application on the command line using the clang compilers and creating Info.plist by a bash script.

How is the "Open with" list populated internally? Is macOS really
scanning my drive looking for Info.plist files with
CFBundleTypeExtensions entries?
I think so, yes. Check the documentation for Launch Services, specifically the section "Application Registration". Specifically, the OS can find your app and register is in the following ways:
A built-in background tool, run whenever the system is booted or a new
user logs in, automatically searches the Applications folders in the
system, network, local, and user domains and registers any new
applications it finds there. (This operation is analogous to
“rebuilding the desktop” in earlier versions of Mac OS.)
The Finder
automatically registers all applications as it becomes aware of them,
such as when they are dragged onto the user’s disk or when the user
navigates to a folder containing them.
When the user attempts to open
a document for which no preferred application can be found in the
Launch Services database, the Finder presents a dialog asking the user
to select an application with which to open the document. It then
registers that application before launching it.
And is there any way to avoid having my "Open with" list littered with older versions other then deleting (or zipping) them?
I'm not sure about that part. Probably not, although it seems like once you reset the Launch Services database using the command in your question, the old versions shouldn't get added back to the Open With list unless you are doing something to trigger getting re-added. Is that the case?

Related

Is it possible to disable mac gatekeeper by extension?

I want to be warned by Mac gatekeeper whenever I attempt to use an app for the first time that is not signed through the store. However, I'm having trouble using LibreOffice Vanilla by clicking on files with relevant extensions (eg .ods, .odt). It seems to consider each file a different app and I think needs me to authorize it individually. Double-clicking file yeilds '"myfile.odt” can’t be opened because it is from an unidentified developer.'
Right-clicking and using Open with ... LibreOffice Vanilla yeilds:
'"myfile.odt” is from an unidentified developer. Are you sure you want to open it?'
I don't find the 'help' at https://support.apple.com/en-ca/HT202491 helpful. How can I configure OS X so it lets me open LibreOffice files with a double-click yet still have GateKeeper check other new applications that are not signed?
You can bypass gatekeeper if you select a file type to "always open with" a certain type of program. Other programs that are not of this type will still invoke gatekeeper, so you won't have the security issues. So if you set your .odt file type to always open with libreoffice, the issue should go away.
See this:
https://apple.stackexchange.com/questions/193233/gatekeeper-wont-let-libreoffice-open-csv-files

Set environment variable for the process before startup

I have the following situation:
I have Mac OS bundle with application which uses some 3rd party dynamic libraries and those libraries depend on some environment variable, let's name it ENV_VAR. I want to set ENV_VAR to some value for my application only because if I set it for the whole system it may breaks some other apps. And it should work transparently to the user i.e. he just run my app from the Application folder by double clicking it. How can I achieve it?
NOTE: dynamic libraries are loaded before main functions starts hence setting this variable in the main doesn't help.
You can add a key "LSEnvironment" to your app bundle's Info.plist. The value can be a dictionary with strings for keys and values and those key-value pairs will be added to the environment when your app is launched by Launch Services (e.g. from the Finder or Dock but not from the Terminal).
<key>LSEnvironment</key>
<dict>
<key>ENV_VAR</key>
<string>value</string>
</dict>
However, in my testing (on Snow Leopard), it was a bit flaky to test, at least when editing the Info.plist of an existing app. Basically, Launch Services caches this part of the app's Info.plist when it first encounters the app and won't necessarily recognize changes on disk. You can sometimes prompt it to reread the Info.plist by, for example, duplicating the app bundle or temporarily moving it to a different folder. Of course, the overkill solution would be to use lsregister to flush and rebuild the cache:
/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -seed
This caching issue won't affect your end users, just you as you tweak the Info.plist. Also, it shouldn't affect you if you make the change in your source Info.plist and then build the app using Xcode.
I am not sure if the following works because I don't have such an app to try. The idea is to set the environment variable from the terminal, then call your application:
ENV_VAR=something open -a YourApplication

Why is my application marking a binary as quarantined?

My (sandboxed) OSX application is trying to launch biber (a bibliography tool for LaTeX). However it fails to launch and I get the following message saying that the application has marked biber as quarantined in Console.App.
25/03/2013 16:44:15.000 kernel[0]: exec of /private/var/folders/s1/70f5my9n6wq0_kk7bcxjslhh0000gn/T/com.abc.XYZ/par-64756e63616e737465656c65/cache-ef42c8d5d44e40bdd24828b0ae70de275e379c88/biber denied since it was quarantined by XYZ and not approved by Gatekeeper, qtn-flags was 0x00000002
This does not happen with any of the other binaries invoked by the application.
This application has an active SSB for the whole harddrive so there are no issues launching, or accessing, external files.
Why and how am I marking that file as quarantined, and how to I remove the quarantine so that it can execute? Thanks for your help.
EDIT If it helps, the contents of that directory are
biber
libperl.dylib
running ls -l#eOd shows them both to have the attribute com.apple.quarantine, however I'm not sure what copied them into that directory, or how they gained that flag. The original copies are not quarantined.
Looks like this 'biber' is not an application download from Mac App Store or identified developers (with Apple Developer ID). So you must manually allow its launch.
Usually there are three ways to do this:
Right click on application and click "Open" from the context menu. There will be a warning, just click "Open". OSX will remember your choice and next time it will open.
You can change Gatekeeper's settings: "System Preferences" -> "Security & Privacy" -> "General" tab. Unlock to make changes. Choose "Anywhere" in the "Allow applications downloaded from" section. Note: it decreases security and there will be a warning about it with the proposal to use first solution.
Remove 'quarantine attribute' from the app. In terminal run command: xattr -d com.apple.quarantine <your_app>
I prefer the last solution. All solutions are for the applications, but I think will also work for the utility.

How does the OS know what to do with a file when the "Open With..." option is selected?

Explanation:
I don't remember about Linux and I don't know about OS X, but in Windows you can right-click a file and select a program to open it. But how does the OS know exactly how to make the program open it? Does it keep track of the "Open file" dialogs the program has? Does the developer have to specify a special event handler or something for these cases?
For Windows, the answer is in the registry. If you're comfortable reading the registry, run regedit.exe on your Windows machine.
Under HKEY_CLASSES_ROOT, you will see a key list of all file types, .doc, .txt, etc. Each of these keys contains a key called "OpenWithList" or "OpenWithProgIds". An application may have a registered "ProgId", also found under HKEY_CLASSES_ROOT, and it can register it's ProgId to the file types it wants to handle in OpenWithProgIds. Otherwise it registers itself in OpenWithList.
In response to the comment to the first answer (cos I don't have enough rep to comment):
You're thinking of DDE, which is a near-enough deprecated technology. The Windows shell executes the application with the selected file as the first parameter.
The Windows Explorer remembers your previous "Open With..." choices based on file extension in the following key:
HKCR\.ext\OpenWithList
Next time you right-click the file, it looks there and build a list of programs you have previously used to open a particular file type.
Say it finds a key named "myapp.exe". It then looks up the application here:
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Applications\myapp.exe
fetches the info where the application is installed. And it goes here:
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\myapp.exe
follows the GUID stored there to find out the display name of the application.
To add to the fun, the primary associated application is in the list as well, also everything in the OpenWithProgIds key and everything in:
HKEY_CLASSES_ROOT\*\OpenWithList
as well as their respective HKEY_CURRENT_USER counterparts.
The resulting list of applications is then made unique, sorted and displayed. On selection the file is started like any other file you click on - i.e.:
C:\path\to\myapp.exe "C:\path\to\the\file.ext"
http://windowsxp.mvps.org/OpenWith.htm
File associations are stored in the Registry in: HKEY_CLASSES_ROOT.
You can manage them graphically by using Windows Explorer: (WinXP)
Click Tools/Options/File Types
Or with the "Default Programs" applet in Control Panel. (Vista)
Just for some nostalgia the rather brilliant Acorn archimedes had a much better system with each file type having a unique type number, with a manufacturer and application code (rather like a MAC address) which was written with the file.
This means you can have different files all called .bak opened by the correct application - unlike the windows case where a new installed app steals the ownership of every exiting file of that type. Autocad is especialy bad for this, registering about 20 file types.
The operating system runs the specified program sending as parameter the path of the file to open.
For example, in C#, if you want to know which file the operating system wants you to open you'll need to do:
class Program
{
static void Main(string[] args)
{
if (args.Length == 1) //The OS wants me to open a file
openSomeFileJustBecauseTheOSWantsIt(args[0]);
}
}

Releasing Windows file share locks

This problem crops up every now and then at work. Our build machine can have it's files accessed via a normal windows file share. If someone browses a folder remotely on the machine, and leaves the window open overnight, then the build fails (as it has done now). The explorer window left opened points at one of the sub folders in the source tree. The build deletes the source, and does a clean checkout before building. The delete is failing.
Right now, I'd like to get the build to work. I'm logged in from home, and I'd rather not reboot the build machine. I'm unable to get hold of the person whose machine is looking and the files, and I can't remotely reboot their machine.
When a windows share has a lock, the locking process is System, so I don't think I can kill it, as with normal locks.
Does anyone know a way to release the lock on a shared folder without having to reboot the machine?
If you are admin on the server sharing the file over the network, you can use the Windows in-built feature:
Start → My Computer → Right-click → Manage gets you to the Computer
Management console
In the left nav, navigate to Systems Tools → Shared Folders
You can view Shares, Sessions & Open Files here. This allows you to find out who has opened which files from which workstations.
Right-click on an item in the list to be able to remove the file lock.
Hope this helps.
Found a solution.
Find the process using Process Explorer:
Download and extract procexp.exe
In Process Explorer use the "Find Handle or DLL..." command from the "Find" menu
Enter in the name of the directory which is having trouble deleting
A list of open files which match that name should be shown. Take some guesses and find which one is failing to be deleted. If the file is locked by a windows share, the process holding the file will be System
Note down the directory which was left open
Download and install the Unlocker (Warning: Link removed, as it contains malware)
Install Unlocker, disabling the option for Explorer extensions and other junk
Unlock the directory
Open up a cmd window, and navigate to C:\Program Files\Unlocker
From the cmd window, run Unlocker.exe "the-path-to-the-locked-folder"
A dialog will pop up confirming the lock release. Use the unlock button to unlock the file
Now the directory should be unlocked, and can now be deleted.
Try Process Hacker:
https://wj32.org/processhacker/
Process hacker is like Process Explorer on steroids.
To find the offending process, press CTRL+F or click the "Find Handles of DLLs" button and search for the file name.
Once you find the file in the find handles dialog, you can simply right click the file there and choose "close". (at least for v2.39.124)
Older versions had a "terminator" option in the context menu of the process.
Right click on the offending process --> Miscellaneous --> Terminator --> Select termination techniques. Note that some are possibly dangerous and may have unintended consequences.
I've had similar problems, and none of these suggestions I've seen above look suitable for automated overnight builds (as the original poster implied) because they all require manual effort to hunt down and kill the locks.
The only method I've tried that seems to work reliably is to remove the share itself, make the build, then add the share back. Here's one way of removing the share automatically:
D:\Projects>net share Projects /DELETE /Y
Users have open files on Projects. Continuing the operation will force the files closed.
Projects was deleted successfully.
(NOTE: Creating the share again automatically can be a pain if the privilege groups you need to give it are messy.)
The way i do it is by using both OpenFiles.exe and Handle.exe
You can run them in any order and you will have your resource fully unlocked.
OpenFiles: to disconnect File Sharing sessions
Handle.exe: to release any open handles (don't try to close handles belonging to pid4, since that's the system process)
You can automate this by using powershell, batch, or any language of your choice.
Another option is, starting from Windows Vista, to use the Windows tool built into the system:
monitor resources: perfmon.exe /res
Extracted from: Http://www.sysadmit.com/2017/06/windows-how-to-know-that-process-has-open-a-file.html

Resources