chdir to the location of the .app bundle in C++ macOS application - c++

I have packaged a macOS binary of an application which loads resources in a folder just outside of the .app bundle. The directory structure looks like
Foo/
Foo.app/
Contents/
...
resources/
I would like to change the working directory of the application to the parent directory Foo/, and this is what I have come up with so far.
#if defined(APPLE)
#include "CoreFoundation/CoreFoundation.h"
#include <unistd.h>
#include <libgen.h>
#endif
int main() {
#if defined(APPLE)
// macOS workaround for setting the working directory to the location of the .app
{
CFBundleRef bundle = CFBundleGetMainBundle();
CFURLRef bundleURL = CFBundleCopyBundleURL(bundle);
char path[PATH_MAX];
Boolean success = CFURLGetFileSystemRepresentation(bundleURL, TRUE, (UInt8 *)path, PATH_MAX);
assert(success);
CFRelease(bundleURL);
chdir(dirname(path));
}
#endif
...
}
This appears to work on macOS 10.7 and 10.10 (which is all I have to test on), but on 10.12, users have reported that resources are not loading, so I suspect that the above hack no longer works correctly.
Is there a better way of changing to the directory of the .app bundle that is being run?

Loading resources from outside of the app bundle is a security vulnerability. Apple has implemented app translocation (a.k.a. path randomization) in 10.12 to prevent it. Their recommended solution is to ship your app in a signed disk image. See here:
Starting in macOS 10.12, you can no longer provide external code or data alongside your code-signed app in a zip archive or unsigned disk image. An app distributed outside the Mac App Store runs from a randomized path when it is launched and so cannot access such external resources. To provide secure execution, code sign your disk image itself using the codesign tool, or distribute your app through the Mac App Store. For more information, see the updated revision to macOS Code Signing In Depth.

Here is another way to do it, but I haven't tested it yet on all the macOS versions. I hope this helps someone, but I'm not accepting it as an answer until I determine it's the best method.
#include <unistd.h> // for chdir
#include <libgen.h> // for dirname
#include <mach-o/dyld.h> // for _NSGetExecutablePath
#include <limits.h> // for PATH_MAX?
char path[PATH_MAX];
uint32_t pathLen = sizeof(path);
int err = _NSGetExecutablePath(path, &pathLen);
assert(!err);
// Switch to the directory of the actual binary
chdir(dirname(path));
// and then go up three directories to get to the folder of the .app bundle
chdir("../../../");

Related

Installed c++ app in usr/local/bin of Ubuntu 16.04 doesn't run correctly when executed from home directory

I have created a deb package out of an c++ programm . I followed this simple guide https://ubuntuforums.org/showthread.php?t=910717. I installed the deb at usr/local/bin successfully.
However I'm facing the following problem. When I run my app from home directory c++ main program starts but when it reaches a point where it needs to read from a settings file it acts as if it does not exist. This file resides in a folder which is in the same place with the c++ executable.
On the other hand when I go to -> usr/local/bin and run my c++ app from there no problem exist. I also have given read write and execute permissions to all files.
Since the /usr/local/bin already exist in my path why this error occurs?
because the application has the current path as your path, not where it's installed. you need to figure out the application path to load the file correctly - if you use Qt you have applicationPath, if not you have to:
char szTmp[32];
sprintf(szTmp, "/proc/%d/exe", getpid());
int bytes = MIN(readlink(szTmp, pBuf, len), len - 1);
if(bytes >= 0)
pBuf[bytes] = '\0';
return bytes;
to determine the application installation folder and load the file based on that.

Application runs fine when built from Xcode, won't run directly from the .app

Working on a c++ mac application in Xcode. When I hit run everything is fine (debug and release mode). But when I go into finder into the Products/Release folder and double click on the .app directly, the app immediately closes with an error (application quit unexpectedly. click report to see more detailed information). When I click report, the line of code it errors on seems to indicate that it isn't finding my resource files, but it finds them fine when I build/run the same exact app from xcode. heres an example of how i use the resource files in the code:
std::ifstream file;
file.open("AppName.app/Contents/Resources/Saves/1.svd");
//do stuff
file.close();
anyone have any ideas why double clicking the .app that xcode just created would have different results than running it from xcode?
also not sure if this is part of the issue, but it seems strange that I have to reference the resource folder from outside the .app file (AppName.app/Contents/Resources/Saves/1.svd). I would expect that path to be relative to the executable in .app/Contents/MacOS like this (../Resources/Saves/1.svd) but that didnt work either.
I had similar problem and spending some time researching different options I ended up using Apple's objects. I needed to get resources folder:
#ifdef __APPLE__
#include "CoreFoundation/CoreFoundation.h"
#endif
Then actual snippet is:
#ifdef __APPLE__
char path[FILENAME_MAX];
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle);
if (!CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8 *)path, PATH_MAX)){
//
//log("CFURLGetFileSystemRepresentation returned false. Path:%s", path);
exit(0);
}
CFRelease(resourcesURL);
chdir(path);
//log("Current path:%s", path);
#endif

The program can't start because opencv_core2410d.dll is missing

I installed visual studio 2012.i have windows 8.1.then i extract opencv 2.4.10 in c partition.
Created the visual C++ project->win32 Console application.
As I have x64 machine
build menu->Configuration manager->platform->x64
then i set below configuration in my vs project.
project->properties->configuration->all configuration
VC++Directories->Library Directories->
C:\opencv\build\x64\vc11\bin,C:\opencv\build\x64\vc11\lib
C/C++->Genaral->Additional Include Derectories->
C:\opencv\build\include,C:\opencv\build\include\opencv2,C:\opencv\build\include\opencv
change the
Configuration->Debug
Select Linker->Input->Additional Dependencies
opencv_core2410d.lib
opencv_highgui2410d.lib
opencv_imgproc2410d.lib
opencv_calib3d2410d.lib
opencv_contrib2410d.lib
opencv_features2d2410d.lib
opencv_flann2410d.lib
opencv_gpu2410d.lib
opencv_legacy2410d.lib
opencv_ml2410d.lib
opencv_nonfree2410d.lib
opencv_objdetect2410d.lib
opencv_photo2410d.lib
opencv_stitching2410d.lib
opencv_superres2410d.lib
opencv_ts2410d.lib
opencv_video2410d.lib
then
change Configuration->Release
select Linker->Input->Additional Dependencies
opencv_core2410.lib
opencv_highgui2410.lib
opencv_imgproc2410.lib
opencv_calib3d2410.lib
opencv_contrib2410.lib
opencv_features2d2410.lib
opencv_flann2410.lib
opencv_gpu2410.lib
opencv_legacy2410.lib
opencv_ml2410.lib
opencv_nonfree2410.lib
opencv_objdetect2410.lib
opencv_photo2410.lib
opencv_stitching2410.lib
opencv_superres2410.lib
opencv_ts2410.lib
opencv_video2410.lib
opencv_videostab2410.lib
then i created a class and wrote the code
#include "stdafx.h"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/core/core.hpp"
int main(){
//declare a new iplimage pointer
IplImage*myimage;
//load image
myimage = cvLoadImage("D:\\visual studio 2012\\katussa.jpg",1);
cvNamedWindow("Smile",1);
cvShowImage("Smile",myimage);
//wait for the key to close the window
cvWaitKey(0);
cvDestroyWindow("Smile");
cvReleaseImage(&myimage);
return 0;
}
when i run i got the error message
The program can't start because opencv_core2410d.dll is missing.
You need to add OpenCV to your system path:
You need to add the directory C:\opencv\build\x86\vc10\bin to your system PATH. This directory contains OpenCV DLLs required for running your code.
Open Control Panel → System → Advanced system settings → Advanced Tab → Environment variables...
On the System Variables section, select Path (1), Edit (2), and type C:\opencv\build\x86\vc10\bin; (3), then click Ok.
ninja edit:
make sure you have follow all the steps on this tutorial
Sometimes you may get this error even when you have added the relevent bin file, for example \opencv-x.x.x\build\install\x64\vc15\bin, to the System Path Environment Variable.
In my case, it worked once I rebooted my PC. Or maybe just restart visual studio and see if it's working, before you reboot the system.

Get working directory on Windows Phone

How to get the current working directory on windows phone?
_wgetcwd and GetCurrentDirectory are not supported on windows phone.
Windows Store Apps don't have the notion of a "current directory" (the OS sets it to be the install location and doesn't let you change it).
The more interesting question is what you want to do with the working directory. Ordinarily, you would use WinRT StorageFile APIs to read and write files, but if you want to use CreateFile or fopen then you can get the path from a WinRT StorageFolder:
void foo()
{
using namespace Windows::ApplicationModel;
using namespace Windows::Storage;
auto installLocation = std::wstring(Package::Current->InstalledLocation->Path->Data());
auto dataLocation = std::wstring(ApplicationData::Current->LocalFolder->Path->Data());
OutputDebugString((installLocation + L"\r\n" + dataLocation).c_str());
}
For my test app, this prints
d:\temp\UniversalScratch\UniversalScratch\UniversalScratch.Windows\bin\x86\Debug\AppX
C:\Users\Peter\AppData\Local\Packages\257de9ed-b378-4811-98e6-226e15a3f7f0_tp1tpcm9wdwpy\LocalState
If you use fopen (or fopen_s) with a relative filename, it will be relative to your install package.

How to use LibVLC with Qt 5

I'm trying to use LibVLC in a Qt 5 program to open a VLC instance and play a video.
The following code comes from https://wiki.videolan.org/LibVLC_Tutorial/
I'm using Linux.
.pro :
TEMPLATE = app
TARGET = projectLoic
INCLUDEPATH += . vlc
QT += widgets
# Input
HEADERS +=
SOURCES += main.cpp
LIBS +=-lvlc
main :
#include <vlc/vlc.h>
#include <QApplication>
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
libvlc_instance_t * inst;
libvlc_media_player_t *mp;
libvlc_media_t *m;
// Load the VLC engine
inst = libvlc_new(0, NULL);
// Create a new item
m = libvlc_media_new_path (inst, "/home/........mp3");
// Create a media player playing environement
mp = libvlc_media_player_new_from_media (m);
// play the media_player
libvlc_media_player_play (mp);
return app.exec();
}
The compilation is fine. But the program immediatly crashes when I build it (with Qt Creator). Any idea?
Many thanks
Many things could cause this crash. The best is to get VLC source code to trace back the issue. Passing the option '--verbose=2' when initializing libVLC can help as well.
In my case the cause of the crash was due to this bug in the ubuntu package of vlc:
https://bugs.launchpad.net/ubuntu/+source/vlc/+bug/1328466
When calling libvlc_new() vlc modules and their dependent libraries are loaded into memory. The qt module of LibVLC was searching for Qt4 shared objects instead of Qt5 (manually installed).
The solution was to rebuild the module cache which was outdated an pointing to Qt4 binaries. You can reset it on the command line:
sudo /usr/lib/vlc/vlc-cache-gen -f /usr/lib/vlc/plugins/
Or pass to vlc the option:
--reset-plugins-cache
I have never used this library, but Are you using exactly this code?
m = libvlc_media_new_path (inst, "/home/........mp3");
This path may be the problem.
What distribution of Linux are you using?
I ran into this same problem with Qt5 and LibVLC, and the primary cause (Ubuntu 12.04 LTS and 14.04 LTS), was that LibVLC was loading the qt4 interface plugin, which conflicted with Qt5. If you check your call stack, you'll most likely see that at a Qt4 library was being loaded, causing the crash.
If this is the problem, there are only 3 options (tested with LibVLC 2.2 and Qt5 on Ubuntu 12.04 and 14.04 LTS 64 bit).
The first (worst) is to delete the qt4 user interface plugin. You can test this is the problem by moving and running and then setting it back. Deleting will break your regular VLC player most likely.
Second option is to create a copy of the plugins directory and set that in your runtime path using VLC_PLUGIN_PATH, environment variable. but I've had trouble getting that to work without changing the original plugin path folder also (which will break your VLC player unless you modify your shortcuts, etc. to also set VLC_PLUGIN_PATH.
The third option, and what I ended up doing, was to custom build my own static LibVLC binary with a few edits to the source code so that it will not load the qt4 interface plugin installed with VLC. You can follow these steps to do this.
1) Download VLC Source Code for your platforms distribution.
http://download.videolan.org/pub/videolan/vlc/
Make sure you download the version matching your distribution. For
example, match the VLC version to what is installed with Ubuntu.
2) Extract source code to folder
3) Install dependencies for the OS distribution
sudo apt-get build-dep vlc
4) Modify src/modules/bank.c
Edit the module_InitDynamic function
Add the following code at the top of the function:
// HACK TO DISABLE QT4 PLUGIN
if(strstr(path, "qt4") != NULL)
return NULL;
// END HACK
3) From terminal
./bootstrap
./configure --disable-qt --disable-skins2 --enable-xcb --prefix=/home/$USER/vlc-custom_build_output_folder_name
./make
./make install
4) Copy/Save the resulting files in the install folder.
Then just link against this library instead.