C++/WinRT handling exceptions from StorageFolder::GetFileAsync - c++-winrt

When no file exists the app throws an exception which I am unable to catch
In my example code below I create a directory "MyFolder" and save a file "" and save a file "sample.txt" to it.
I then call the function FindFileAsync twice - first using the already created file "sample.txt" which works fine and then using a non-existing file "nofile.txt" which fails with the error
Exception thrown at 0x00007FF94E39D759 in FindFile.exe: Microsoft C++ exception: winrt::hresult_error at memory location.
Is there any solution to this issue.
MainPage.h
#pragma once
#include "MainPage.g.h"
namespace winrt::FindFile::implementation
{
struct MainPage : MainPageT<MainPage>
{
MainPage();
Windows::Foundation::IAsyncAction FindFileAsync(hstring value);
Windows::Foundation::IAsyncAction GetFolderAsync(hstring const& value);
Windows::Foundation::IAsyncAction CreateFileAsync(hstring const& fname);
Windows::Foundation::IAsyncAction DeletefileAsync(Windows::Storage::StorageFile const & value);
void ClickHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args);
private:
hstring folderDir{ L"MyFolder" };
};
}
namespace winrt::FindFile::factory_implementation
{
struct MainPage : MainPageT<MainPage, implementation::MainPage>
{
};
}
MainPage.cpp
#include "pch.h"
#include "MainPage.h"
#include "MainPage.g.cpp"
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::UI::Xaml;
using namespace Windows::Storage;
using namespace Windows::Storage::Streams;
using namespace Windows::UI::Popups;
namespace winrt::FindFile::implementation
{
MainPage::MainPage()
{
InitializeComponent();
}
Windows::Foundation::IAsyncAction MainPage::FindFileAsync(hstring value)
{
Windows::Storage::StorageFolder storageFolder{ Windows::Storage::ApplicationData::Current().LocalFolder() };
StorageFolder sampleFolder{ co_await storageFolder.CreateFolderAsync(folderDir, CreationCollisionOption::OpenIfExists) };
try
{
Windows::Storage::StorageFile manifest{ co_await sampleFolder.GetFileAsync(value) };
}
catch (winrt::hresult_error msg)
{
hstring ms{ msg.message() };
MessageDialog dlg(ms, L"File Error");
dlg.ShowAsync();
}
}
Windows::Foundation::IAsyncAction MainPage::GetFolderAsync(hstring const& value)
{
Windows::Storage::StorageFolder storageFolder{ Windows::Storage::ApplicationData::Current().LocalFolder() };
auto sampleFolder{ co_await storageFolder.CreateFolderAsync(value, CreationCollisionOption::OpenIfExists) };
}
IAsyncAction MainPage::CreateFileAsync(hstring const& fname)
{
Windows::Storage::StorageFolder storageFolder{ Windows::Storage::ApplicationData::Current().LocalFolder() };
auto sampleFolder{ co_await storageFolder.CreateFolderAsync(folderDir, CreationCollisionOption::OpenIfExists) };
auto sampleFile{ co_await sampleFolder.CreateFileAsync(L"sample.txt", Windows::Storage::CreationCollisionOption::ReplaceExisting) };
co_await Windows::Storage::FileIO::WriteTextAsync(sampleFile, L"Swift as a shadow");
}
IAsyncAction MainPage::DeletefileAsync(StorageFile const& value)
{
co_await value.DeleteAsync();
}
void MainPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
hstring fname{ L"sample.txt" };
GetFolderAsync(folderDir);
CreateFileAsync(fname);
// The following statement is successful as the file exists
FindFileAsync(fname);
// The following ststement throws an exception error
FindFileAsync(L"nofile.txt");
}
}

In C++/WinRT, some exceptions, but not all, force the debugger to pause program execution despite the exception being handled (thrown inside a try block). However, you can resume it by pressing F5 or launching the app without a debugger (CTRL+F5 or via the start menu). I'm not sure whenever this is a bug or intended behavior.

I have found a solution that worked for me.
When the debugger triggers the exception the message includes a checked checkbox. If unchecked and the program is continued to the end the problem is resolved. When run again the error is not triggered and the catch can handle the "file not found". Not sure why the default setting is to trigger the exception.

Related

C++/WinRT: MIDL 3.0 type: Char - compile of generated code returns 'T must be WinRT type'. Is there a support usage?

Using the idl source containing the MIDL 3.0 simple type Char:
namespace BrokenMIDL_Char
{
[default_interface]
runtimeclass MainPage : Windows.UI.Xaml.Controls.Page
{
MainPage();
Int32 MyProperty;
Char MyStationLetter_1;
//Char MyStationLetter_2;
//Char MyStationLetter_3;
}
}
And the supporting functions
wchar_t MyStationLetter_1()
{
throw hresult_not_implemented();
}
void MyStationLetter_1(wchar_t /*value*/)
{
throw hresult_not_implemented();
}
char16_t MyStationLetter_2()
{
throw hresult_not_implemented();
}
void MyStationLetter_2(char16_t /*value*/)
{
throw hresult_not_implemented();
}
char MyStationLetter_3()
{
throw hresult_not_implemented();
}
void MyStationLetter_3(char /*value*/)
{
throw hresult_not_implemented();
}
Results in an error
T must be a WinRT type
My understanding was that the MIDL 3.0 types are the definition the WinRT types.
The MIDL compiler emits:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
template<typename TDeclaringType, typename TValue>
void SetValueTypeMember_MyStationLetter_1(
::winrt::Windows::Foundation::IInspectable const& instance,
::winrt::Windows::Foundation::IInspectable const& value)
{
instance.as<TDeclaringType>().MyStationLetter_1(::winrt::unbox_value<TValue>(value));
}
During testing, I have a solution you could make a try.
You could open the Property tab > Properties > Configuration Properties > C/C++ > Language, find Treat Wchar_t As Built in Type property and select the No(/Zc:wchar_t-) option. Then, try to build your project.

How to append text to file in a UWP app

I need to create a simple log class (just a "save to file" method) in a UWP app for debugging purpose but AppendTextAsync is much different from ofstream and I don't know how to use.
This is my class
#pragma once
ref class winRTLog sealed
{
public:
winRTLog();
void save(Platform::String^ log);
private:
Platform::String^ myFilename = L"myLog.txt";
Windows::Storage::StorageFolder^ myFolder;
Windows::Storage::StorageFile^ myFile;
Windows::Foundation::IAsyncOperation<Windows::Storage::StorageFile^>^ createMyFile;
concurrency::task<Windows::Storage::StorageFile^> myFileTask;
};
and here's the mess I've written so far trying to understand the documentation
#include "pch.h"
#include <ppltasks.h>
#include "winRTLog.h"
winRTLog::winRTLog()
{
myFolder = Windows::Storage::ApplicationData::Current->LocalFolder;
createMyFile = myFolder->CreateFileAsync(myFilename, Windows::Storage::CreationCollisionOption::OpenIfExists);
myFileTask = concurrency::create_task(myFolder->GetFileAsync(myFilename));
//how to make myFile point the file I've created?
}
void winRTLog::save(Platform::String^ log)
{
//??
myFileTask.then([&]()
{
//how to use Windows::Storage::FileIO::AppendTextAsync
//with myFile and log?
});
}
Don't use StorageFile APIs for saving data into local folder. Only use it if you need to: for APIs that require you passing them in a storage file or to access a place like pictures library which doesn't have a real path. StorageFile APIs are terribly slow compared to traditional APIs. Worst of all, all of the file operations are asynchronous, which means they're a pain to work with and even a bigger pain to debug.
For your scenario, I'd just use std::wofstream if you're familiar with it:
#include <fstream>
class winRTLog
{
public:
winRTLog(Platform::String^ fileName);
void save(Platform::String^ log);
private:
std::wofstream m_OutStream;
};
winRTLog::winRTLog(Platform::String^ fileName) :
m_OutStream(std::wstring(Windows::Storage::ApplicationData::Current->LocalFolder->Path->Data()) + L"\\" + fileName->Data(), std::ios::app)
{
if (!m_OutStream.is_open())
throw std::runtime_error("Failed to open the log file.");
}
void winRTLog::save(Platform::String^ log)
{
m_OutStream << log->Data();
if (m_OutStream.fail())
throw std::runtime_error("Failed to write to the log file.");
}
Alternatively, you can use Win32 file APIs:
#include <memory>
#include <string>
#include <windows.h>
class winRTLog
{
public:
winRTLog(Platform::String^ fileName);
~winRTLog();
void save(Platform::String^ log);
private:
HANDLE m_LogHandle;
};
winRTLog::winRTLog(Platform::String^ fileName)
{
auto filePath = std::wstring(Windows::Storage::ApplicationData::Current->LocalFolder->Path->Data()) + L"\\" + fileName->Data();
m_LogHandle = CreateFile2(filePath.c_str(), GENERIC_WRITE, 0, OPEN_ALWAYS, nullptr);
if (m_LogHandle == INVALID_HANDLE_VALUE)
throw std::runtime_error("Failed to open the log file: error code " + std::to_string(GetLastError()));
if (SetFilePointer(m_LogHandle, 0, nullptr, FILE_END) == INVALID_SET_FILE_POINTER)
throw std::runtime_error("Failed to set file pointer to the end of file: error code " + std::to_string(GetLastError()));
}
winRTLog::~winRTLog()
{
if (m_LogHandle != INVALID_HANDLE_VALUE)
CloseHandle(m_LogHandle);
}
void winRTLog::save(Platform::String^ log)
{
// Convert to UTF8
std::string utf8;
utf8.resize(4 * log->Length());
auto utf8Length = WideCharToMultiByte(CP_UTF8, 0, log->Data(), static_cast<int>(log->Length()), &utf8[0], static_cast<int>(4 * log->Length()), nullptr, nullptr);
if (utf8Length == 0)
throw std::runtime_error("Failed to convert log message to UTF8: error code " + std::to_string(GetLastError()));
utf8.resize(utf8Length);
// Write to actual log
DWORD bytesWritten;
auto writeResult = WriteFile(m_LogHandle, utf8.data(), static_cast<DWORD>(utf8.length()), &bytesWritten, nullptr);
if (writeResult == FALSE || bytesWritten != utf8.length())
throw std::runtime_error("Failed to write log message to the log file: error code " + std::to_string(GetLastError()));
}
Note, I used throwing std::runtime_error for error handling for example purposes: you might want to do it differently.
Based on the answer by #Sunius, but for C++/WinRT in a UWP app, noting that the log file will be in the %appdata%\..\Local\Packages\<YOUR_UWP_APP PACKAGE>\LocalState folder:
// WinRtLog.cpp
#include "WinRtLog.h"
#include "winrt/Windows.Storage.h"
using namespace winrt::Windows;
winRTLog::winRTLog(std::wstring fileName) :
m_OutStream(std::wstring(Storage::ApplicationData::Current().LocalFolder().Path().data()) + L"\\" + fileName, std::ios::app)
{
if (!m_OutStream.is_open())
throw std::runtime_error("Failed to open the log file.");
}
void winRTLog::save(std::string log)
{
m_OutStream << log.data();
if (m_OutStream.fail())
throw std::runtime_error("Failed to write to the log file.");
}
And the header:
// WinRtLog.h
#pragma once
#include <fstream>
#include "winrt/Windows.ApplicationModel.Core.h"
class winRTLog
{
public:
winRTLog(std::wstring fileName);
void save(std::string log);
private:
std::wofstream m_OutStream;
};
Note that the broadFileSystemAccess capability is needed in your UWP Package.appxmanifest if the log file is to be stored in an arbitrary folder -- this capability must be set in code (the Appx GUI will not show it) as shown in this SO post.

Qt5 QNetworkAccessManager finished signal never emits

I have a very confusing problem.
I had a simple project that was downloading files from some ftp servers. It worked very good.
Then, I tried implementing that same code into a larger project (first one was a Console App, and the second one is GUI, but I don't think that changes anything..).
After doing some debugging it seems to me that finished() signal from QNetworkAccessManager somehow never gets emitted (or received).
Again, the exact same lines of code work as a separate project.
downloader.h
#ifndef DOWNLOADER_H
#define DOWNLOADER_H
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QFile>
#include <QDebug>
class Downloader : public QObject
{
Q_OBJECT
public:
explicit Downloader(QObject *parent = 0);
signals:
void dloadend();
void printed();
public slots:
void replyFinished (QNetworkReply *reply);
void doDownload(QUrl url);
void printDLend();
private:
QNetworkAccessManager *manager;
};
#endif // DOWNLOADER_H
downloader.cpp
#include "downloader.h"
Downloader::Downloader(QObject *parent) :
QObject(parent)
{
}
void Downloader::doDownload(QUrl url)
{
qDebug()<<"entry: doDownload\n";
QNetworkRequest req(url);
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)),this,SLOT(printDLend()));//SLOT(replyFinished(QNetworkReply*)));
manager -> get(req);
qDebug()<<"exit: doDownload\n";
}
void Downloader::replyFinished (QNetworkReply *reply)
{
qDebug()<<"entry: reply\n";
if(reply->error()) {
qDebug() << "ERROR!";
qDebug() << reply->errorString();
}
else
{
qDebug() << "Download finished!";
QFile *file = new QFile("C:/users/jelicicm/Desktop/test1.hex");
if(file->open(QFile::Append))
{
file->write(reply->readAll());
file->flush(); file->close();
qDebug() <<"Downloaded file size:" <<file->size() <<"Bytes";
qDebug() <<"File name: "<< file->fileName();
;
}
delete file;
}
reply->deleteLater();
manager->deleteLater();
emit dloadend();
}
mainwindow.cpp (important part)
void MainWindow::on_actionDownloadFirmwareImage_triggered()
{
Downloader d;
QUrl url("ftp://ftp.xenbase.org/pub/Genomics/JGI/Xenla6.0/Xenla_6.0_JGI_Gene_Models.fasta.tgz");
qDebug() << "url, debug";
ui->plainTextEdit->appendPlainText(url.toDisplayString());
d.doDownload(url);
QObject::connect(&d,SIGNAL(dloadend()),this, SLOT(printDLend()));
}
Can't get my head around this.
Any help is welcome,
Thanks!
EDIT> More info:
Debugger posts this>
url, debug
entry: doDownload
exit: doDownload
You create object Downloader on stack and it is deleted right after your function exits. You must create object using new, and provide MainWindow object as parent, so after you close MainWindow, the object will be destroyed.
If the download finish, you still need to destroy the object, so simply connect the dloadend() signal to deleteLater() slot, Qt loop will delete your object right after all signal are processed.
void MainWindow::on_actionDownloadFirmwareImage_triggered()
{
Downloader *d = new Downloader(this);
QUrl url("ftp://example.com/some.file.tgz");
qDebug() << "url, debug";
ui->plainTextEdit->appendPlainText(url.toDisplayString());
d->doDownload(url);
QObject::connect(d,SIGNAL(dloadend()),this, SLOT(printDLend()));
QObject::connect(d,SIGNAL(dloadend()), d, SLOT(deleteLater()));
}

Immediate Access Violation when debugging Windows.Devices.Sensors project in Windows 7

I have a large solution with 50+ unmanaged projects in it. I have recently added a project with managed code in it to the solution. The managed code accesses Windows.Devices.Sensors in a .NET dll. This dll is eventually wrapped by unmanaged code and called from another unmanaged project.
My problem is that I get the following access violation before main() even executes.
Unhandled exception at 0x744b8ea0 in myApplication.exe: 0xC0000005: Access violation.
Managed code:
#using <Windows.winmd>
using namespace Windows::Devices::Sensors;
#include <math.h>
namespace TabletSensors
{
namespace NET
{
public ref class DotNetDllClass
{
public:
DotNetDllClass()
{
Initialization();
}
~DotNetDllClass()
{
}
float* GetQuaternion()
{
OrientationSensorReading^ reading = _orientation->GetCurrentReading();
if( reading != nullptr )
{
float* quat = new float[4];
quat[0] = reading->Quaternion->X;
quat[1] = reading->Quaternion->Y;
quat[2] = reading->Quaternion->Z;
quat[3] = reading->Quaternion->W;
return quat;
}
else
{
return NULL;
}
}
private:
void Initialization()
{
_orientation = OrientationSensor::GetDefault();
if( _orientation != nullptr )
{
_orientation->ReportInterval = 16;
}
else
{
// not good ... throw exception or something
}
}
OrientationSensor^ _orientation;
};
}
}
Wrapper header file:
namespace TabletSensors
{
namespace NETWrapper
{
class DLLEXPORT_SENSORS WrapperClass
{
public:
__stdcall WrapperClass();
__stdcall ~WrapperClass();
float* __stdcall GetQuaternion();
};
}
}
Wrapper cpp file:
#define MIXSENSORS_BUILD
#include <gcroot.h>
#include "DotNetWrapper.h"
#include "DotNetDll.h"
using namespace TabletSensors::NETWrapper;
using namespace TabletSensors::NET;
static gcroot<TabletSensors::NET::DotNetDllClass^> Sensors = nullptr;
static System::UInt16 refCount = 0;
#pragma managed
inline TabletSensors::NET::DotNetDllClass^ GetSensors(void)
{
return (TabletSensors::NET::DotNetDllClass^)Sensors;
}
void Init()
{
++refCount;
if(GetSensors() == nullptr)
{
Sensors = gcnew TabletSensors::NET::DotNetDllClass();
}
}
void CleanUp()
{
if( refCount > 0 )
{
--refCount;
}
}
float* GetQuaternion_()
{
return Sensors->GetQuaternion();
}
#pragma unmanaged
TabletSensors::NETWrapper::WrapperClass::WrapperClass()
{
Init();
}
TabletSensors::NETWrapper::WrapperClass::~WrapperClass()
{
CleanUp();
}
float* TabletSensors::NETWrapper::WrapperClass::GetQuaternion()
{
float* x = new float[4];
return GetQuaternion_();
}
#pragma managed
Unmanaged project referencing my wrapper class:
#include "DotNetWrapper.h"
.
.
.
void UnmanagedProject::Update()
{
// if this line is present, I get an access violation without hitting any breakpoints.
TabletSensors::NETWrapper::WrapperClass _tabletSensors;
.
.
.
}
Since the managed code is trying to access Tablet Sensors I understand why it doesn't work on my Windows 7 desktop. What I don't understand it why it won't even allow me to debug my code at all. No breakpoints are hit before the Access Violation occurs.
What I would really like to figure out is how to use exception handling or #ifdefs to keep this crash from happening. But I have had very little luck.
Any ideas?
The fix is to Delay Load the managed DLL. The allows the application to run until that DLL is explicitly called. Thanks to Ben Voight for his answer here: https://stackoverflow.com/a/28467701/1454861

MFC DLL: class object value is not persisting throughout the exported call

I have written MFC dll having 3 methods are exported. I have declared class object as global and initialized it in first method then second and third method use and process it.
Issue is that class obeject's value is not getting persisting throughout the file. when second or third method gets call from C# client application, class
object value is getting NULL.
Could anybody tell me why this is happening! I have tried this same scnaerio in another application but this issue is not reproduced.
Code:
Interface File:
#include "StdAfx.h"
#define DLLEXPORT __declspec(dllexport)
using namespace nsAnalyzer;
static CWindowsAnalyzer *pWindowsAnalyzer = NULL;
extern "C" DLLEXPORT void Init( const wchar_t *sCurrentUserDataDir,
const wchar_t *sMachineName,
const wchar_t *sMacId )
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
try
{
nsAnalyzer::CWindowsAnalyzer *pWindowsAnalyzer = new CWindowsAnalyzer( CString(sCurrentUserDataDir),
CString(sMachineName),
CString(sMacId) );
if(pWindowsAnalyzer)
{
pWindowsAnalyzer->Init();
}
}
catch(const std::exception& e)
{
cout<<"Error: Exception occured in Init: "<<e.what()<<endl;
}
}
extern "C" DLLEXPORT bool Analyze()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
bool bResult = false;
try
{
if(pWindowsAnalyzer->ConsolidateRawActivities())
{
cout<<"ConsolidateRawActivities succeed"<<endl;
bResult = true;
}
else
{
cout<<"ConsolidateRawActivities failed"<<endl;
bResult = false;
}
}
catch(const std::exception& e)
{
cout<<"Error: Exception occured in Analyze: "<<e.what()<<endl;
}
return bResult;
}
extern "C" DLLEXPORT void Dispose()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
try
{
// Disponse windows analyzer
if(pWindowsAnalyzer)
{
delete pWindowsAnalyzer;
}
// Dispose Logger
CLogger::DisposeInstance();
}
catch(const std::exception& e)
{
cout<<"Error: Exception occured in Dispose: "<<e.what()<<endl;
}
}