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.
Related
I have a UWP app that launches a C++ console app (not a Windows runtime component or anything related to UWP). I need the UWP app to pass a file path to the C++ console app so the console app can process it.
For reference, I followed these blog posts:
https://stefanwick.com/2018/04/06/uwp-with-desktop-extension-part-1/
https://stefanwick.com/2018/04/06/uwp-with-desktop-extension-part-2/
As for the parameters, I have this code in my Package.appxmanifest file:
<Extensions>
<desktop:Extension xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
Category="windows.fullTrustProcess"
Executable="PTSExtractionWRT\PTSExtractionWRT.exe">
<desktop:FullTrustProcess>
<desktop:ParameterGroup GroupId="ExistingFile" Parameters="/existingFile"/>
</desktop:FullTrustProcess>
</desktop:Extension>
</Extensions>
and I launch the console app like so from MainPage.xaml.cs
if (ApiInformation.IsApiContractPresent("Windows.ApplicationModel.FullTrustAppContract", 1, 0))
{
// store command line parameters in local settings so Launcher can retrieve them
ApplicationData.Current.LocalSettings.Values["parameters"] = filePath;
var appData = ApplicationData.Current.LocalSettings;
await Windows.ApplicationModel.FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync("ExistingFile");
}
The problem is that the filePath variable I'm sending is getting stored in the C:\Users\14087\AppData\Local\Packages\23930191-5d12-44d5-81c3-808263a5b2f9_qe1bgctg42gkj\Settings\settings.dat file with this path, and I can't find a way to access this file from the C++ console app.
What is being sent as arguments to the C++ app is "/existingFile" from the Package.appxmanifest file.
How can I retrieve the real parameter?
Referring to the document, you could configure your pure c++ console app with the Microsoft.Windows.CppWinRT NuGet package to enable the c++ console app use C++/WinRT APIs, so that you can get the parameters by using ApplicationData API in C++ console project.
Please check the following steps for your c++ console project:
Open the NuGet Package Manager(option Tools > NuGet Package Manager > Manage NuGet Package for Solution…).
Input cppwinrt in Browse page, find Microsoft.Windows.CppWinRT and install it for your c++ console project.
Open the Properties page for your c++ console project, in Configuration Properties > General page, set the option C++ Language Standard as ISO C++ 17 Standard(/std:c++ 17).
In your c++ console project, add the necessary header file and code to test the ApplicationData API, for example:
#include <iostream>
#include <winrt/Windows.Storage.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
int main()
{
std::cout << "Hello World!\n";
winrt::Windows::Storage::ApplicationDataContainer localSettings= winrt::Windows::Storage::ApplicationData::Current().LocalSettings();
auto values = localSettings.Values();
//values.Insert(L"exampleSetting", winrt::Windows::Foundation::PropertyValue::CreateString(L"Hello Windows"));
winrt::hstring val = winrt::unbox_value<winrt::hstring>(values.Lookup(L"parameters"));
std::wcout << val.c_str() << std::endl;
system("PAUSE");
}
For more information about C++/WinRT, you could refer to the document.
Is there a way for a C++ or Objective-C program to tell whether is it being run as a command-line application (e.g. with ./myprog in a shell) or as an app bundle (e.g. by double-clicking on a .app in Finder or running open myprog.app/ in Terminal)?
Currently I'm using the following.
CFBundleRef bundle = CFBundleGetMainBundle();
CFURLRef bundleUrl = CFBundleCopyBundleURL(bundle);
char bundleBuf[PATH_MAX];
CFURLGetFileSystemRepresentation(bundleUrl, TRUE, (UInt8*) bundleBuf, sizeof(bundleBuf));
At this point, bundleBuf now holds the path to the .app bundle or the directory containing the command-line executable. I can check whether the string ends with ".app", but this is hacky. Is there a better way to do this?
You can query the Uniform Type Identifier (UTI) of the URL (using CFURLCopyResourcePropertyForKey() with kCFURLTypeIdentifierKey) and see if it conforms to kUTTypeApplicationBundle (using UTTypeConformsTo()).
CFStringRef uti;
if (CFURLCopyResourcePropertyForKey(bundleUrl, kCFURLTypeIdentifierKey, &uti, NULL) &&
uti &&
UTTypeConformsTo(uti, kUTTypeApplicationBundle))
{
// Is bundled application
}
Using Objective-C, you can use the NSWorkspace methods -typeOfFile:error: and -type:conformsToType: for the same purpose.
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("../../../");
Linux seems to be easy: xdg-open <file/directory/URL>.
Apparently, Mac is similar: open should be used instead of xdg-open. I don't have access to a Mac so I couldn't test it.
For Windows, I found 4 different suggestions and those that I have tried failed.
Is there a non-java, cross platform way to launch the associated application for a certain file type?
suggests start
How to give focus to default program of shell-opened file, from Java? suggests
cmd /c start ...
How to open user system preferred editor for given file?
How to Find Out Default File Opener with Java?
suggest RUNDLL32.exe
What is the correct way to use ShellExecute() in C to open a .txt
Open file with Windows' native program within C++ code
How to use ShellExecute to open html files in Windows using C++? suggest
ShellExecute
I have tried the first 3 with system() and QProcess::startDetached() and "http://www.stackoverflow.com" as argument but they all failed; start works just fine from the command line though. I haven't tried ShellExecute yet.
What is the Windows equivalent of xdg-open? It seem to me, it is start but why did my attempts with start fail?
Is ShellExecute my only option?
EDIT I thought QDesktopServices::openUrl() was for web pages only because it did not work for files or directories.
After some debugging I figured out that if I replace \\ with / in the path on Windows, it works for files but the directories are still not opened. Any ideas what I am doing wrong?
QDir dir("C:/Documents and Settings/ali");
qDebug() << "Exists? " << dir.exists();
qDebug() << dir.absolutePath();
QDesktopServices::openUrl(QUrl(dir.absolutePath()));
qDebug() << "External app called";
Application Output:
Exists? true
"C:/Documents and Settings/ali"
External app called
But nothing happens, the directory is not opened. On Linux, directories are opened with the default file manager as expected.
SOLUTION: Due to the Qt bug and Windows quirks (malformed application window), I ended up using ShellExecute. That gives me enough flexibility to achieve exactly what I want at some expense...
Why don't you just use Qt's support for this? For example:
QDesktopServices::openUrl(QUrl("/home/realnc/test.pdf"));
This opens the document in Acrobat Reader. In general, it obeys the preferred application settings in my OS for all file types that have one or more applications associated with them. Best of all, it's platform-independent.
Edit:
The fact that it opens directories on Linux but not on Windows smells like a bug. It might be best to report this on Qt's bug tracker. In the meantime, you could have a workaround for Windows for when the file is a directory:
#ifdef Q_WS_WIN
if (QFileInfo(path).isDir())
QProcess::startDetached("explorer", QStringList(path));
else
#endif
QDesktopServices::openUrl(QUrl(path));
You can also do it with cmd.exe's start command, but you'll get an ugly terminal pop up for a few fractions of a second:
QProcess::startDetached("cmd", QStringList() << "/C" << "start"
<< QDir::toNativeSeparators(path));
I'm trying to compile and run the app, which was created 4 years ago. It was developed for Windows in Embarcadero RAD Studio C++ builder. Now I try to compile and run it in Windows in VirtualBox using the latest version of RAD Studio. I have a system call to another app in my app:
system("dot.exe -Tjpg -o nfa.jpg NFA_graph.txt");
It keeps returning 1 and the file is not created. I also tried
system("Echo %CD% >> z:\log.txt");
and the file is not created. I also tried like this:
FILE *fpipe;
char *command = "Echo %CD% >> z:\log.txt";
char line[256];
if (0 == (fpipe = (FILE*)_popen(command, "r")))
{
perror("popen() failed.");
exit(1);
}
while (fread(line, sizeof line, 1, fpipe))
{
ShowMessage(line);
}
_pclose(fpipe);
And nothing I get. I wonder if the reason of such strange behaviour is that I'm running this all in VirtualBox?
You're not escaping your \ characters. You should use / in file paths, or \\ if you must. In addition, Windows 7 won't let you write to the root directory of a hard drive w/o administrator access.
To determine if a command environment is available, first do this:
if (!system(NULL)) {
// Can't make any system() calls
}
If your command environment is available, then you need to fully specify the path, making sure to escape the \'s like I mentioned above, and don't write anything to a drive's root directory. Also make note that opening files does not default create directories.
No, it's very unlikely. I see few issues with your code: you did not check errno if system() returns 1. It can help you to spot a real problem. Also, all backslashes must be Esc'ed.
I'm suggesting that dot.exe is not in PATH environment variable, that's the reason of the system() failure.