std::ifstream::open() fails in Windows 10 Universal apps - c++

I'm working on a Windows 10 Universal C++ project and I'm trying to open a binary file in read-mode using std::ifstream.
This is my code:
std::ifstream imgFile("C:\\Users\\GuiTeK\\Desktop\\picture.bmp", std::ios::binary);
if (imgFile.is_open())
{
std::cout << "OK" << std::endl;
}
else
{
int error = errno;
std::cerr << "KO: " << error << std::endl;
}
Problem is that it keeps failing with error 13, which means "The data is invalid" (C.F. System Error Codes).
However, the exact same code works fine in a Win32 Console Application C++ project.
What's wrong?

UWP apps do not have permission to access all files on the device. By default, apps can access certain file system locations such as application install directory or application data locations. For more info, please see File access permissions.
"C:\Users\GuiTeK\Desktop\picture.bmp" is a location that you app can't directly access. In UWP, we will need a File​Open​Picker to access such a file. One important rule here is that Skip the path: stick to the StorageFile.
For more info about how to handle files in UWP, please see Files, folders, and libraries and also File access sample, File picker sample on GitHub.

Related

How to pass parameters from UWP app to pure C++ console app?

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.

Using custom script files with C++ project in Visual Studio 2019

TL;DR
My project uses a custom script file at runtime.
My project builds fine in VS and runs on the command line.
However when running in VS an error is thrown implying the file doesn't exist.
Full Details
My c++ project uses a custom scripting file to apply some settings at run time:
these are javascript like but not actual javascript
having these settings not in compiled files means they may be changed without recompiling
Everything builds fine, the script is copied using xcopy in a post build event.
When running in VS2019 it doesn't seem to be able to find the scripting file.
An opaque, library specific error is issued: A GenApi error has occurred
But when running the resulting .exe from cmd everything works, the script is used no problem.
If the script file is removed from the output dir and the .exe is run again I get the same A GenApi error has occurred.
I have tried:
running in release and debug.
including and excluding the file from the build.
I don't want to debug the script, I just need it to be used during start up so I can debug the rest of the program which is in C++.....
Example Code
Main.cpp
#include <iostream>
#include <EGrabber.h>
void configure() {
Euresys::EGenTL gentl;
Euresys::EGrabber<> grabber(gentl);
grabber.runScript("config.js");
}
int main() {
try {
configure();
} catch (const std::exception &e) {
std::cout << "error: " << e.what() << std::endl;
}
}
config.js
var grabber = grabbers[0];
var FPS = 150;
// camera configuration
grabber.RemotePort.set("TriggerMode", "On");
grabber.RemotePort.set("TriggerSource", "CXPin");
grabber.RemotePort.set("ExposureMode", "TriggerWidth");
// frame grabber configuration
grabber.DevicePort.set("CameraControlMethod", "RG");
grabber.DevicePort.set("CycleTriggerSource", "Immediate");
grabber.DevicePort.set("CycleMinimumPeriod", 1e6 / FPS);
More info:
script documentation
based on #john 's comment:
There is a different current working directory when running from VS and when running from the command line.
When run from VS the current working directory is the project directory not the output directory.
The script was in project-dir\src not the immediate project dir.
Moving the script up to the project directory solved everything.
Alternative solutions, which worked:
Use the full path: C:\\full\\path\\config.js
(the application startup path can be extracted from argv[0])
Change the debug working directory in VS:
Project -> Properties -> Configuration Properties -> Debugging -> Working Directory
Enter output path, eg: $(SolutionDir)bin$(Platform)$(Configuration)\

osx: external program (qprocess) crash if parent run with open, but works fine if parent run directly

I faced the strange situation on MacOS 10.13 and can't find what is the root of it.
I have 32-bit Qt application packed in a bundle. Because of MacOS limitation for one of the operations I need to start small 64-bit console binary that does a trick. This console binary placed in Contents/MacOS and I start it using QProcess.
Everything works fine if I run the main application from IDE. Also, everything fine if I open a terminal, cd to Contents/MacOS and run the main application directly.
But once I use "open myApp.app" or start it via UI, then QProcess exitCode() returns 255, which seems to mean crash.
Code for starting subprocess:
QProcess p;
p.start("./papply", QStringList() << osid << filepath);
p.waitForFinished(5000);
qDebug() << p.readAllStandardOutput();
qDebug() << p.readAllStandardError();
qDebug() << p.state();
if(p.state()==QProcess::Running)
{
qDebug() << "peapply freezed - kill";
p.kill();
return false;
}
qDebug() << "Apply" << osid << filepath << "=" << p.exitCode();
return p.exitCode()==0;
Any help will be very appreciated.
I have 32-bit Qt application packed in a bundle.
Firstly, just in-case you missed this, Apple have stated that the next version of the OS (10.14) will not support 32-bit applications, so you'll need to change this if you want to run this application on future versions of macOS.
If you use the debugger, or run a binary from a bundle's Contents/MacOS folder, it executes directly. In contrast, if you double-click on a binary, or use the open keyword from the terminal, a request is sent to Launch Services, to open the application on your behalf.
Launch Services (LS) maintains an association to an application's Bundle Identifier, which is located in the application bundle's Info.plist file.
When a request to open an application with LS occurs, LS is presented with the Bundle Identifier, from the application's plist and LS will execute the application that has been registered, with that identifier.
In the plist, we also have the key CFBundleExecutable, which is defined as the "(Recommended) Name of the bundle's executable file". This is the name of the binary that will likely be executed, residing in the Contents/MacOS folder.
Note, since LS launches the application associated with the given identifier, if there is a copy of the same application on your machine, with the same version number and identifier, it may not be necessarily executing the application you double-clicked, to run.
Therefore, the reason for the crash is most likely due to a different application being launched by LS and not the one you think is being executed. Ensure you have no other copies of the application residing on the machine.
If a crash report is generated, you should be able to see the path to the application, at the start of the images section, where it includes paths to dynamic libraries and frameworks.
While #TheDarkKnight provided great information that is not exactly an answer.
For people who will face the same situation:
In macOS bundle application has working directory related to bundle, but not to the execution file itself as it happens in Windows.
So in my case next code works:
QString path = qApp->applicationDirPath();
if(!path.endsWith("/"))
path += "/";
QProcess p;
p.start(path + "papply", QStringList() << osid << filepath);

C++ file permissions when automatically started by Windows on login

Problem: my C++ program cannot write to a file after reboot because it is denied access.
The program is added into the registry at the following location, thus enabling it during start up:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run
The following snipper within the code is similar to the one that is causing the problems:
ofstream myfile;
myfile.open ("example.txt", ios:app);
myfile << "Writing this to a file.\n";
myfile.close();
Because this snippet of code runs within a loop the file is repeatedly opened and closed, but when the computer is rebooted the program seems to loose file permissions to it, and .open says it got an Acess Denied error with respect to the file.
What is the problem here? How come the program runs when it is initiated by me without admin rights, but not when Windows initiates it?
As I understand the problem is not in C++ libs but in rights that your application has when windows run it. So, try the following:
1) create shortcut for your exe-file;
2) in HKEY_CURRENT_USER\...\Run change name of application from *.exe to *.lnk (just to run application with help of shortcut);
3) in the shortcut's properties in the Advanced Security Settings section change OWNER to SYSTEM.
perhaps this helps.
"example.txt" is relative to your working directory, which is probably different when run at startup. Add a hardcoded path to test this hypothesis.

How to launch the associated application for a file / directory / URL?

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));