C++/CX - GetFileAsync throws breakpoint error - c++

I am trying to open a xml file from my Assets folder, but unfortunately I am only able to open my xml file by using a FileOpenPicker which is not the most ideal situation when I have to constantly fetch my xml file, without disturbing the user of course.
FileOpenPicker^ openPicker = ref new FileOpenPicker();
openPicker->ViewMode = PickerViewMode::List;
openPicker->SuggestedStartLocation = PickerLocationId::Desktop;
openPicker->FileTypeFilter->Append(".xml");
task<StorageFile^>(
openPicker->PickSingleFileAsync()).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->LoadAsync(stream->Size);
String^ strXml = reader->ReadString(stream->Size);
});
}
});
I am now trying to reconstruct this code into a code which loads up my xml file without letting the user choose. I tried the following approach:
String^ xmlFile = "Assets\MyXmlFile.xml";
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->LoadAsync(stream->Size);
String^ strXml = reader->ReadString(stream->Size);
stream->FlushAsync();
});
}
});
I think I get errors at the GetFileAsync which I am not able to solve and I am asking you, the community to try and help me.

Your code worked for me with one modification: the xmlFile string contains a backslash that needs to be escaped:
String^ xmlFile = "Assets\\MyXmlFile.xml";
Note also that if you just right-clicked "Assets" in your project and chose "Add new item", that item may have ended up in your root project folder (which is the default). If you want it to be deployed to the Assets subfolder it will need to physically live there on disk in the assets subdirectory, not just be in the Assets filter. (Unlike in C#, the C++ project "folders" are actually filters and do not reflect physical directory location.)

Related

Pulling Drive activity report through GCP, is there a way to see folder path?

I am supposed to generate drive activity report so we can track what type of file users are using and where is the file being created (My Drive/shared drive).
I used the GAM command to pull drive activity report which has various fields except for the root path.
Does anyone know a way i can manipulate that so i can get a field that shows folder path as well.
Thanks!
You can try these particular GAM commands so you can edit them later to gather information of the folders and root folders:
gam user <User Email Address> print filetree depth 0 showmimetype gfolder excludetrashed todrive
You can edit the depth, for example orphaned folders when using -1. I am not familiar with which command you use, but you might need to mix or add some fields so it shows the root folder or path.
gam user <User Email Address> print filelist todrive select 1Yvxxxxxxxxxxxxxxxxxxxxxxjif9 showmimetype gfolder fields id
You might need to add over your command something like "print filetree" or "show filepath"
Reference:
https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files-Display
I have created a custom menu that iterates through a table of data, the data must have a column with the file IDs of interest and 2 additional columns for owner and path, since the file can be owned by either a user or a shared drive. The user running the function must have Super Admin rights to access files owned by other users and the user in question must be a member of a shared drive for the file to be located. My previous implementation as a custom function failed to address a limitation of this feature where advanced services are inaccessible.
The custom menu is created as explained in this documentation article https://developers.google.com/apps-script/guides/menus. There must be a trigger that executes when the sheet opens the menu is created.
In addition to that the code requires the use of Advanced Services, Google Drive must be added following the steps of this other article https://developers.google.com/apps-script/guides/services/advanced#enable_advanced_services. The advanced service will ask for authorization but the first time the code is executed. You may expedite the process by creating an empty function and running it.
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('File ownership').addItem('Read data', 'readData').addToUi();
}
function readData() {
var sheetData = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
var i = 0;
for (; i < sheetData.length; i++){
if (sheetData[0][i] == '')
break;
}
SpreadsheetApp.getUi().alert('There are ' + i + ' cells with data.');
for (i = 1; i < sheetData.length; i++){
var fileID = sheetData[i][0];
var owner = getFileOwner(fileID);
var path = getFilePath(fileID);
SpreadsheetApp.getActiveSheet().getRange(i + 1,2).setValue(owner);
SpreadsheetApp.getActiveSheet().getRange(i + 1,3).setValue(path );
}
SpreadsheetApp.getUi().alert('The owner and file path have been populated');
}
function getFilePath(fileID, filePath = ""){
try {
var file = Drive.Files.get(fileID,{
supportsAllDrives: true
});
if (!file.parents[0])
return "/" + filePath;
var parent = file.parents[0];
var parentFile = Drive.Files.get(parent.id,{ supportsAllDrives: true });
var parentPath = parentFile.title;
if (parent.isRoot || parentFile.parents.length == 0)
return "/" + filePath;
else {
return getFilePath(
parentFile.id,
parentPath + "/" + filePath);
}
}
catch (GoogleJsonResponseException){
return "File inaccesible"
}
}
function getFileOwner(fileID){
try {
var file = Drive.Files.get(
fileID,
{
supportsAllDrives: true
});
var driveId = file.driveId;
if (driveId){
var driveName = Drive.Drives.get(driveId).name;
return driveName + "(" + driveId + ")";
}
var ownerEmailAddress = file.owners[0].emailAddress;
return ownerEmailAddress;
}
catch (GoogleJsonResponseException){
return "File inaccesible"
}
}
After executing the function, it will take significantly longer the more files IDs it has, the cells will be updated with their respective owner and path.
Note: with a Super Admin account you can programmatically create a view permission for shared drives you don't have access to using APIs or Apps Script, you may submit a separate question for more details or read the documentation in the developer page at https://developers.google.com/drive/api/v2/reference/permissions.

Delete file with BIM360 API Issue

My aim is to Upload files into a specific subfolder of the "Plans" folder. The first problem I got was that I can only upload a file with version 1, when I use the API. So I decided to copy all files from the specific folder into an archive folder. Now I can delete all files from the specific folder, that I can upload the new files to the specific folder. I am using the forge-api-dotnet-client.
I know there are two different ways of deleting files. (https://forge.autodesk.com/blog/way-delete-file-version-through-forge-dm-api)
I tried both of them but they did not work.
let project =
{ Id = "projectId"
ProjectFilesFolder = "specificFolderId"
UploadFolder = "destinationFolderId" }
let itemName = "itemName"
let itemId = "urn:adsk.wipprod:dm.lineage:QCtjhnZ5TWWCASh-mQ5nmA"
let createVersionBody fileName itemId =
sprintf """{
"jsonapi":{
"version":"1.0"
},
"data":{
"type":"versions",
"attributes":{
"name":"%s",
"extension":{
"type":"versions:autodesk.bim360:Deleted",
"version":"1.0"
}
},
"relationships":{
"item":{
"data":{
"type":"items",
"id":"%s"
}
}
}
}
}""" fileName itemId
|> JsonConvert.DeserializeObject<CreateVersion>
let versionApi = VersionsApi()
let result = versionApi.PostVersion(project.Id, (createVersionBody itemName itemId))
result |> ignore
It gives me this BAD_INPUT Exception and I found that I get a different id from the api than from the webpage.
ItemId from Api: "urn:adsk.wipprod:dm.lineage:QCtjhnZ5TWWCASh-mQ5nmA"
ItemId from Webpage: "urn:adsk.wipprod:dm.lineage:EdJjPVzFQR6tlbUJ5WK-zg"
The second way I found was to do it with "DeleteObject".
let project =
{ Id = "projectId"
ProjectFilesFolder = "specificFolderId"
UploadFolder = "destinationFolderId" }
let getStorage = ifcs project
ObjectsApi().DeleteObject(getStorage.BucketKey, getStorage.ObjectName)
I get this exception .
I am using a TwoLegged Authentication and my scope is also fine.
Is there an error in my code or is there another way of doing it?

Accessing uploaded files from Camunda task

The final task of a Camunda process must write the files uploaded by the user to an specific folder. So, I've created the following 'Service task' as the last one of the process:
Then, from the Java project, I've added the FinishArchiveDelegate class with the following code:
package com.ower.abpar.agreements;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;
public class FinishArchiveDelegate implements JavaDelegate {
#Override
public void execute(DelegateExecution execution) throws Exception {
System.out.println("Process finished: "+execution.getVariables());
}
}
When I check the logs, I see that I can see the document names, like:
document_1 => FileValueImpl [mimeType=image/jpeg, filename=Test_agreement1.jpg, type=file, isTransient=false]
The problem is that it only shows the file name and I'd need to request it from Camunda's database to copy it to another folder. Any suggestion or idea?
Thanks!
After some tests, I realized that I can get not only the name but all the uploaded files content using execution.getVariable(DOCUMENT_VARIABLE_NAME). So this is what I did:
// Get the uploaded file content
Object fileData = execution.getVariable("filename");
// The following returns a FileValueImpl object with metadata
// about the uploaded file, such as the name
FileValueImpl fileMetadata = FileValueImpl)execution.getVariableLocalTyped("filename")
// Set the destination file name
String destinationFileName = DEST_FOLDER + fileMetadata.getFilename();
...
// Create an InputStream from the file's content
InputStream in = (ByteArrayInputStream)fileData;
// Create an OutputStream to copy the data to the destination folder
OutputStream out = new FileOutputStream(destinationFileName);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
Hope this helps someone, cheers!

Loading a file into a C++ object from an iOS App / issues with <iostream> on iOS

I'm working on integrating a C++ library (the GRT, a machine learning toolkit, to be specific) inside of an iOS app.
I've built the GRT as a framework, including using some Objective-C++ wrapper functions to call between my app and the framework.
At the moment, I'm trying to troubleshoot something involving file loading. Specifically, I'm trying to load a file from my app bundle into a GRT module.
Here's where I get the file I want access to, and initialize the GRT wrapper:
func loadTrainingData(){
let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let fileUrl = documentsUrl.appendingPathComponent("train.grt")
let pipeline = GestureRecognitionPipeline()
let test:Bool = pipeline.load(fileUrl.path)
print(test)
}
And here's the Obj-C++ wrapper code that's called when pipeline.load is called:
- (BOOL)load:(NSString *) path
{
BOOL result = self.instance->load(std::string(path.UTF8String));
if (result) {
std::cout << "GRT config";
std::cout << self.instance->getModelAsString();
std::cout << "GRT info: " << self.instance->getInfo();
}
return result;
}
Finally, here's the actual C++ code that's part of the GRT library, where file loading is handled:
bool GestureRecognitionPipeline::load(const std::string &filename){
std::fstream file;
//Clear any previous setup
clear();
file.open(filename.c_str(), std::iostream::in );
if( !file.is_open() ){
errorLog << __GRT_LOG__ << " Failed to open file with filename: " << filename << std::endl;
return false;
}
...
}
Currently, I'm always failing to have my pipeline object successfully import a file. I don't think it's necessarily something to do with the way I'm accessing the file on the iOS side (though, I could be wrong). Does anyone have any insight? Any appreciated - thanks!
EDIT: I was able to verify that I am loading my file is being loaded properly by this check:
let path = Bundle.main.path(forResource: "acc-orientation", ofType: "grt")
print(path as Any!)
But, I'm still getting the same issues as before.
EDIT 2 I verified that the path is being loaded correctly in the the Obj-C++ wrapper too; which leads me to think it may be something related to the way that is handled in iOS....totally lost here now...
EDIT 3 As suggested by a colleague, I tried using the absoluteString of the file url to pass to my wrapper and the underlying C++ code, since the C++ doesn't have access to the sandboxed environment of iOS. Still the same result:
let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let fileUrl = documentsUrl.appendingPathComponent("acc-orientation.grt")
let pipeline = GestureRecognitionPipeline()
let test:Bool = pipeline.load(fileUrl.absoluteString)
EDIT 4 As suggested in the comments, I tried using fileSystemRepresentation, but this also didn't bring success.
- (BOOL)load:(NSURL *) url {
BOOL result = self.instance->load(std::string([url fileSystemRepresentation]));
...
}
EDIT 5: I made a simple test project that attempts to only access the file and load it using Swift->Obj-C++->C++ (no framework files, in other words). Here's a link where it can be downloaded. Any help appreciated!
Well, you are almost there. I have downloaded your sample project and got it working. Your problem has to do with the actual location of the file you want to open. At the moment you are trying to open the file from the Documents folder but you never actually copy the file from the App Bundle to the Documents folder. So there are two solutions:
Solution 1: App Bundle
Alter the loadTrainingData method in ViewController.swift to access the file from the App Bundle:
func loadTrainingData(){
let path = Bundle.main.url(forResource: "acc-orientation", withExtension: "grt")
let wrapper = Wrapper()
let test:Bool = wrapper.load(path)
print(test)
}
Solution 2: Documents folder
Copy the file from your App Bundle to your Documents folder right after the first launch. Therefore, copy the following code snippet to your AppDelegate.swift:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
do {
let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("acc-orientation.grt")
let bundleURL = Bundle.main.url(forResource: "acc-orientation", withExtension: "grt")
try FileManager.default.copyItem(at: bundleURL!, to: url)
} catch {
print("File already exists")
}
return true
}
With either of these solutions your FileLoader::load method will return true.
Hope that helps.

How do we register Shell extension with a certain file extension

I have tested a small shell extension referring to the article on code project. Though the whole process is quite complicated , I have some how idea what are the follwoing methodsand what do thet do.:
Initialize,DragQueryFile,GetCommandString,InvokeCommand,QueryContextMenu
But after reading through it I can not understand how Our ContextMenu Extension is being associated with .txt file.
The article explains if we will have a look inside .rgs file we can see that it create a registry entry like this:
HKCR
{
NoRemove txtfile
{
NoRemove ShellEx
{
NoRemove ContextMenuHandlers
{
ForceRemove SimpleShlExt = s '{5E2121EE-0300-11D4-8D3B-444553540000}'
}
}
}
}
But in actual, after following the article and writing the code , when I opened SimpleShlExt.rgs It looks something like this:
--Edit As in CodeProject--
HKCR
{
NoRemove CLSID
{
ForceRemove {1E569362-E0A6-4DEA-AB1F-67D6D3DEF1A5} = s 'SimpleShExt Class'
{
InprocServer32 = s '%MODULE%'
{
val ThreadingModel = s 'Apartment'
}
}
}
}
Does the registry Dynamically creating any mapping bettwen the CLSID and txtfile reg entry.
If that is the case , if I want to modify the behaviour for any other File , for example for mp3 file or drive itself and I want my Context menu to Pop-Up or displayed , then how to go about it. Because I don't know the CLSID for that.
One possibility is to register your context menu for all the file extensions you want to support. The other possibility is to register your extension in the wildcard / * class. It will then be instanciated for all files. You can then decide whether the context menu should be visible for this file or not. This can be done by using the IDataObject argument of IShellExtInit::Initialize.
You have to add the part to register with the txt file extension manually to your rgs file. Visual Studio only adds the part to register the shell extension.
Assuming your lib's uuid is 5E2121EE-0300-11D4-8D3B-444553540000, then use the following to associate your shell extension with *.txt and *.tab files. Add another block per each new extension:
NoRemove .txt
{
NoRemove shellex
{
{00021500-0000-0000-C000-000000000046} = s '{5E2121EE-0300-11D4-8D3B-444553540000}'
}
}
NoRemove .tab
{
NoRemove shellex
{
{00021500-0000-0000-C000-000000000046} = s '{5E2121EE-0300-11D4-8D3B-444553540000}'
}
}