When the app is registered to handle a file extension and a file with that extension is opened the WSA build will be notified of the file in the following auto generated code found in App.xaml.cpp:
void App::OnFileActivated(FileActivatedEventArgs^ args)
{
String^ appArgs = "File=";
m_SplashScreen = args->SplashScreen;
bool firstFileAdded = false;
for (auto file : args->Files)
{
if (firstFileAdded)
{
appArgs += ";";
}
else
{
firstFileAdded = true;
}
appArgs += file->Path;
}
InitializeUnity(appArgs);
}
I can then get access to this file path from within Unity using the following code:
public class HoloLensExternalDataInput : MonoBehaviour
{
// Use this for initialization
void Start ()
{
UnityEngine.WSA.Application.windowActivated += Application_windowActivated;
}
private void Application_windowActivated(UnityEngine.WSA.WindowActivationState state)
{
if (state != UnityEngine.WSA.WindowActivationState.Deactivated)
{
var arguments = UnityEngine.WSA.Application.arguments;
Debug.Log("Application_windowActivated - arguments: " + arguments);
const string FILE_ARG = "File=";
const string UIR_ARG = "Uri=";
if (arguments.StartsWith(FILE_ARG))
{
var filesStr = arguments.Substring(FILE_ARG.Length);
var files = filesStr.Split(';');
if (files.Length > 0)
{
Debug.Log("External File: " + files[0]);
#if ENABLE_WINMD_SUPPORT
var storeageFile = System.Threading.Tasks.Task.Run(async () => { return await Windows.Storage.StorageFile.GetFileFromPathAsync(files[0]); }).Result;
Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.Add(storeageFile);
#endif
DataLoadManager.LoadExternalFile(files[0]);
}
}
else if (arguments.StartsWith(UIR_ARG))
{
var uri = arguments.Substring(UIR_ARG.Length);
//TODO: handel URI
}
}
}
}
The problem is 2 fold.
First, I shouldn’t have to call “Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.Add” myself. The auto generated code should do this, otherwise the file path passed into Unity is useless and cannot be accessed.
The second problem is that now that I have to compile with IL2CPP instead of the .NET backend because I switched to Unity 2019, this workaround no longer works. One of the two lines after “#if ENABLE_WINMD_SUPPORT” (my guess is the task runner) crashes with the following exception:
UnauthorizedAccessException: Attempted to perform an unauthorized operation.
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x00000] in <00000000000000000000000000000000>:0
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x00000] in <00000000000000000000000000000000>:0
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00000] in <00000000000000000000000000000000>:0
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00000] in <00000000000000000000000000000000>:0
at System.Runtime.CompilerServices.StrongBox1[T]..ctor (T value) [0x00000] in <00000000000000000000000000000000>:0 at EWIHARParser.PropertyValue+<GetEnumerator>d__8..ctor (System.Int32 <>1__state) [0x00000] in <00000000000000000000000000000000>:0 at System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner.InvokeMoveNext (System.Object stateMachine) [0x00000] in <00000000000000000000000000000000>:0 at System.Threading.ContextCallback.Invoke (System.Object state) [0x00000] in <00000000000000000000000000000000>:0 at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in <00000000000000000000000000000000>:0 at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in <00000000000000000000000000000000>:0 at System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner.Run () [0x00000] in <00000000000000000000000000000000>:0 at System.Action.Invoke () [0x00000] in <00000000000000000000000000000000>:0 at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction (System.Action action, System.Boolean allowInlining, System.Threading.Tasks.Task& currentTask) [0x00000] in <00000000000000000000000000000000>:0 at System.Threading.Tasks.Task.FinishContinuations () [0x00000] in <00000000000000000000000000000000>:0 at System.Threading.Tasks.Task.FinishStageThree () [0x00000] in <00000000000000000000000000000000>:0 at System.Threading.Tasks.Task.FinishStageTwo () [0x00000] in <00000000000000000000000000000000>:0 at System.Threading.Tasks.Task.Finish (System.Boolean bUserDelegateExecuted) [0x00000] in <00000000000000000000000000000000>:0 at System.Threading.Tasks.Task
1[TResult].TrySetException (System.Object exceptionObject) [0x00000] in <00000000000000000000000000000000>:0
at System.Threading.Tasks.TaskCompletionSource1[TResult].TrySetException (System.Exception exception) [0x00000] in <00000000000000000000000000000000>:0 at System.Threading.Tasks.AsyncInfoToTaskBridge
1[TResult].Complete (Windows.Foundation.IAsyncInfo asyncInfo, System.Func2[T,TResult] getResultsFunction, Windows.Foundation.AsyncStatus asyncStatus) [0x00000] in <00000000000000000000000000000000>:0 at System.Threading.Tasks.AsyncInfoToTaskBridge
1[TResult].CompleteFromAsyncOperation (Windows.Foundation.IAsyncOperation1[TResult] asyncInfo, Windows.Foundation.AsyncStatus asyncStatus) [0x00000] in <00000000000000000000000000000000>:0 at Windows.Foundation.AsyncOperationCompletedHandler
1[TResult].Invoke (Windows.Foundation.IAsyncOperation1[TResult] asyncInfo, Windows.Foundation.AsyncStatus asyncStatus) [0x00000] in <00000000000000000000000000000000>:0 Rethrow as AggregateException: One or more errors occurred. at System.Threading.Tasks.Task.ThrowIfExceptional (System.Boolean includeTaskCanceledExceptions) [0x00000] in <00000000000000000000000000000000>:0 at System.Threading.Tasks.Task
1[TResult].GetResultCore (System.Boolean waitCompletionNotification) [0x00000] in <00000000000000000000000000000000>:0
at System.Threading.Tasks.Task`1[TResult].get_Result () [0x00000] in <00000000000000000000000000000000>:0
at HoloLensExternalDataInput.Application_windowActivated (UnityEngine.WSA.WindowActivationState state) [0x00000] in <00000000000000000000000000000000>:0
at UnityEngine.WSA.WindowActivated.Invoke (UnityEngine.WSA.WindowActivationState state) [0x00000] in <00000000000000000000000000000000>:0
at UnityEngine.WSA.Application.InvokeWindowActivatedEvent (UnityEngine.WSA.WindowActivationState state) [0x00000] in <00000000000000000000000000000000>:0
My preferred fix would be for Unity to add the call to “Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.Add” to the auto generated code in App.xaml.cpp. But until that is done can someone help me figure out a workaround?