C++/CX WinRT File Copy - c++

I'm really suffering through the WinRT Windows::Storage namespace with all it's asyncronousness.
I have the following private members in my header file:
//Members for copying the SQLite db file
Platform::String^ m_dbName;
Windows::Storage::StorageFolder^ m_localFolder;
Windows::Storage::StorageFolder^ m_installFolder;
Windows::Storage::StorageFile^ m_dbFile;
And I have the following code block in my implementation file:
//Make sure the SQLite Database is in ms-appdata:///local/
m_dbName = L"DynamicSimulations.db";
m_localFolder = ApplicationData::Current->LocalFolder;
m_installFolder = Windows::ApplicationModel::Package::Current->InstalledLocation;
auto getLocalFileOp = m_localFolder->GetFileAsync(m_dbName);
getLocalFileOp->Completed = ref new AsyncOperationCompletedHandler<StorageFile^>([this](IAsyncOperation<StorageFile^>^ operation, AsyncStatus status)
{
m_dbFile = operation->GetResults();
if(m_dbFile == nullptr)
{
auto getInstalledFileOp = m_installFolder->GetFileAsync(m_dbName);
getInstalledFileOp->Completed = ref new AsyncOperationCompletedHandler<StorageFile^>([this](IAsyncOperation<StorageFile^>^ operation, AsyncStatus status)
{
m_dbFile = operation->GetResults();
m_dbFile->CopyAsync(m_localFolder, m_dbName);
});
}
});
I get a memory access violation when it gets to m_dbFile = operation->GetResults();
What am I missing here? I come from a c# background in which this is really easy stuff to do :/
I've tried using '.then' instead of registering the event but I couldn't even get those to compile.
thank you for your help!

If you are interested in the WinRT solution, here it is:
It seems all you want to do is to copy the DB file from the installed location into the local folder. For that the following code should suffice:
//Make sure the SQLite Database is in ms-appdata:///local/
m_dbName = L"DynamicSimulations.db";
m_localFolder = ApplicationData::Current->LocalFolder;
m_installFolder = Windows::ApplicationModel::Package::Current->InstalledLocation;
create_task(m_installFolder->GetFileAsync(m_dbName)).then([this](StorageFile^ file)
{
create_task(file->CopyAsync(m_localFolder, m_dbName)).then([this](StorageFile^ copiedFile)
{
// do something with copiedFile
});
});

I've tried this thing before. Don't do this:
if(m_dbFile == nullptr)
Instead verify the value of "status".
if(status == AsyncStatus::Error)

Related

Files added to MockFileSystem don't have Exists = true when returned from FileInfo.FromFileName()

Also found on...
https://github.com/System-IO-Abstractions/System.IO.Abstractions/issues/393
(But there's a wider audience here)
In a test I have the following:
var testSettings = new ApplicationSettings() { DefaultLedgerFilename = testLedgerFilename };
//Add the byte array as file data
var fileData = new MockFileData(testSettings); //I added an overload PR #389
//Create a file system with the fake data as a "file"
var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
{
{ AppDomain.CurrentDomain.BaseDirectory+"MoneyTrackerConfig.config", fileData }
});
In the codebase I have the following:
var tempFile = _fileSystem.FileInfo.FromFileName(_path);
if (tempFile.Exists && (tempFile.Length > 0))
{
...
The problem is when I run the test 'tempFile.Exists' returns 'false'. Even if I create the file on the drive it returns 'false'. What am I doing wrong?
Found the issue.
After a day of debugging (that included digging into and debugging the System.IO.Abstractions source) I realized that I missed a backslash.
Yup, pure user error. Note the line above
{ AppDomain.CurrentDomain.BaseDirectory+"MoneyTrackerConfig.config", fileData }
... it should be ...
{ AppDomain.CurrentDomain.BaseDirectory+#"\MoneyTrackerConfig.config", fileData }
Sorry for anyone that took this seriously. I feel ridiculous.

C++/CX - DataReader out of bounds exception

I have the following code which opens a file and it works most of the time for one time. After that I get exceptions thrown and I don't know where the problem is hiding. I tried to look for this for a couple of days already but no luck.
String^ xmlFile = "Assets\\TheXmlFile.xml";
xml = ref new XmlDocument();
StorageFolder^ InstallationFolder = Windows::ApplicationModel::Package::Current->InstalledLocation;
task<StorageFile^>(
InstallationFolder->GetFileAsync(xmlFile)).then([this](StorageFile^ file) {
if (nullptr != file) {
task<Streams::IRandomAccessStream^>(file->OpenAsync(FileAccessMode::Read)).then([this](Streams::IRandomAccessStream^ stream)
{
IInputStream^ deInputStream = stream->GetInputStreamAt(0);
DataReader^ reader = ref new DataReader(deInputStream);
reader->InputStreamOptions = InputStreamOptions::Partial;
reader->LoadAsync(stream->Size);
strXml = reader->ReadString(stream->Size);
MessageDialog^ dlg = ref new MessageDialog(strXml);
dlg->ShowAsync();
});
}
});
The error is triggered at this part of the code:
strXml = reader->ReadString(stream->Size);
I get the following error:
First-chance exception at 0x751F5B68 in XmlProject.exe: Microsoft C++ exception: Platform::OutOfBoundsException ^ at memory location 0x02FCD634. HRESULT:0x8000000B The operation attempted to access data outside the valid range
WinRT information: The operation attempted to access data outside the valid range
Just like I said, the first time it just works but after that I get the error. I tried detaching the stream and buffer of the datareader and tried to flush the stream but no results.
I've also asked this question on the Microsoft C++ forums and credits to the user "Viorel_" I managed to get it working. Viorel said the following:
Since LoadAsync does not perform the operation immediately, you should probably add a corresponding “.then”. See some code: https://social.msdn.microsoft.com/Forums/windowsapps/en-US/94fa9636-5cc7-4089-8dcf-7aa8465b8047. This sample uses “create_task” and “then”: https://code.msdn.microsoft.com/vstudio/StreamSocket-Sample-8c573931/sourcecode (file Scenario1.xaml.cpp, for example).
I have had to separate the content in the task<Streams::IRandomAccessStream^> and split it up in separate tasks.
I reconstructed my code and I have now the following:
String^ xmlFile = "Assets\\TheXmlFile.xml";
xml = ref new XmlDocument();
StorageFolder^ InstallationFolder = Windows::ApplicationModel::Package::Current->InstalledLocation;
task<StorageFile^>(
InstallationFolder->GetFileAsync(xmlFile)).then([this](StorageFile^ file) {
if (nullptr != file) {
task<Streams::IRandomAccessStream^>(file->OpenAsync(FileAccessMode::Read)).then([this](Streams::IRandomAccessStream^ stream)
{
IInputStream^ deInputStream = stream->GetInputStreamAt(0);
DataReader^ reader = ref new DataReader(deInputStream);
reader->InputStreamOptions = InputStreamOptions::Partial;
create_task(reader->LoadAsync(stream->Size)).then([reader, stream](unsigned int size){
strXml = reader->ReadString(stream->Size);
MessageDialog^ dlg = ref new MessageDialog(strXml);
dlg->ShowAsync();
});
});
}
});

MapReduce - code written in configure is not reachable

I wanted to move some files to the input folder and tried the required code by placing it in configure() method (I had to use Old mapred API, due to some constraints i have).
But, some how the code in configure is not being executed.
I have achieved my requirement though in other better way. Though this is a stupid idea, I wanted to know why it is not being executed. I have checked the job tracker and all variables got the right values
Code:
in main:
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String date = sdf.format(new Date());
if(args[3].toString().equalsIgnoreCase("net")){
imgInpPath = "/user/mapreduce/output/net/"+date+"/";
inputDir = inputDir+"net/";
}
conf.set("imgInpPath", imgInpPath);
conf.set("inputDir", inputDir);
FileInputFormat.setInputPaths(conf,inputDir);
in configure()
inputPath = conf.get("inputDir");
Path inputImgPath = new Path(conf.get("imgInpPath"));
Configuration config = new Configuration();
FileSystem fileSystem = FileSystem.get(config);
inputImgPath = fileSystem.makeQualified(inputImgPath);
FileStatus[] status = fileSystem.listStatus(inputImgPath, new PathFilter(){
#Override
public boolean accept(Path name) {
return name.getName().contains("part");
}});
for(int i=0; i <status.length;i++)
{
Path inpPath = status[i].getPath();
FileUtil.copy(fileSystem, inpPath, fileSystem, new Path(inputPath), true , conf);
}
As i said, required thing is achieved in other way. But, I wanted to know, why this is not being performed, irrespective of the requirement.

Subsonic 3 Save() then Update()?

I need to get the primary key for a row and then insert it into one of the other columns in a string.
So I've tried to do it something like this:
newsObj = new news();
newsObj.name = "test"
newsObj.Save();
newsObj.url = String.Format("blah.aspx?p={0}",newsObj.col_id);
newsObj.Save();
But it doesn't treat it as the same data object so newsObj.col_id always comes back as a zero. Is there another way of doing this? I tried this on another page and to get it to work I had to set newsObj.SetIsLoaded(true);
This is the actual block of code:
page p;
if (pageId > 0)
p = new page(ps => ps.page_id == pageId);
else
p = new page();
if (publish)
p.page_published = 1;
if (User.IsInRole("administrator"))
p.page_approved = 1;
p.page_section = staticParent.page_section;
p.page_name = PageName.Text;
p.page_parent = parentPageId;
p.page_last_modified_date = DateTime.Now;
p.page_last_modified_by = (Guid)Membership.GetUser().ProviderUserKey;
p.Add();
string urlString = String.Empty;
if (parentPageId > 0)
{
urlString = Regex.Replace(staticParent.page_url, "(.aspx).*$", "$1"); // We just want the static page URL (blah.aspx)
p.page_url = String.Format("{0}?p={1}", urlString, p.page_id);
}
p.Save();
If I hover the p.Save(); I can see the correct values in the object but the DB is never updated and there is no exception.
Thanks!
I faced the same problem with that :
po oPo = new po();
oPo.name ="test";
oPo.save(); //till now it works.
oPo.name = "test2";
oPo.save(); //not really working, it's not saving the data since isLoaded is set to false
and the columns are not considered dirty.
it's a bug in the ActiveRecord.tt for version 3.0.0.3.
In the method public void Add(IDataProvider provider)
immediately after SetIsNew(false);
there should be : SetIsLoaded(true);
the reason why the save is not working the second time is because the object can't get dirty if it is not loaded. By adding the SetIsLoaded(true) in the ActiveRecord.tt, when you are going to do run custom tool, it's gonna regenerate the .cs perfectly.

Subsonic 3 Simple Repository And Transactions

So this is what I have so far. Am I doing something wrong or is there a bug in 3.0.0.3?
var Repository = new SimpleRepository("DBConnectionName");
using (TransactionScope ts = new TransactionScope())
{
using (SharedDbConnectionScope scs = new SharedDbConnectionScope("connstring", "providerName"))
{
try
{
for (int i = 0; i < 5; i++)
{
Supplier s = new Supplier();
s.SupplierCode = i.ToString();
s.SupplierName = i.ToString();
Repository.Add<Supplier>(s);
}
ts.Complete();
}
catch
{
}
}
}
I'm getting an error in SubSonic DbDataProvider
public DbConnection CurrentSharedConnection
{
get { return __sharedConnection; }
protected set
{
if(value == null)
{
__sharedConnection.Dispose();
etc..
__sharedConnection == null :( Object Null Reference Exception :(
Finally solved this for myself. All of the above code does not work for me (SubSonic 3.0.0.3, using SQLite) but adding BeginTransaction() caused it to work as expected, greatly speeding up the transaction and rolling back the updates if any exceptions occur.
using (SharedDbConnectionScope sharedConnectionScope = new SharedDbConnectionScope(Access.Provider))
{
using (IDbTransaction ts = sharedConnectionScope.CurrentConnection.BeginTransaction())
{
IRepository repo = new SimpleRepository(Access.Provider);
//Do your database updates
//throw new ApplicationException("Uncomment this and see if the updates get rolled back");
ts.Commit();
}
}
For completeness: Access.Provider is a static property in a helper class for me that returns return SubSonic.DataProviders.ProviderFactory.GetProvider(ConnectionString, "System.Data.SQLite");
Perhaps switching the SharedDbConnectionScope and TransactionScope around may help.
using (SharedDbConnectionScope scs = new SharedDbConnectionScope("connstring", "providerName"))
{
using (TransactionScope ts = new TransactionScope())
{
}
}
This will happen when Migration is set - On tablemigration the dbconnection will be closed.
Try the SimpleRepository with SimpleRepositoryOptions.None.
Don't know if this is a bug. I think the transactions don't work with SimpleRepository, I've always half of the data saved when throwing an exception in the transaction... perhaps it's only for ActiveRecord? Anybody knows?