0

I am confronted to a simple example of couroutine in a UWP application but cannot find out how to achieve it.

Here is my purpose: given a path on a disk and a base folder, I want to create the folder hierarchy associated. for example: base folder: "c:\test\" path: "test1\test2\test3"

my purpose is to create the folders test1, test2 and test3 so we have following folder structure: c:\test\test1\test2\test3\

Here is what I did so far: I parse the path so I have its different components (test1, test2 and test3) in an array (subfolders in the following example)

        Windows::Storage::StorageFolder^ current_storage_folder = base_folder;
        for (auto& subfolder : subfolders)
        {
            if (!subfolder.empty())
            {
                Windows::Storage::StorageFolder^ next_storage_folder = (Windows::Storage::StorageFolder^)co_await current_storage_folder->TryGetItemAsync(subfolder);
                if (next_storage_folder == nullptr)
                {
                    next_storage_folder = co_await current_storage_folder->CreateFolderAsync(subfolder);
                }
                current_storage_folder = next_storage_folder;
            }

        }

The output I get is wrong, as I have test1 which is created, sometimes test2. however, result cannot be predicted.

I think my understanding of co_await is wrong, as I expect each co_await call to finish before getting to the next call, which do not seem to be the case.

Rudy_FnP
  • 41
  • 8
  • Did you mean `CreateFolderAsync(subfolder);` instead of `subfolder_mng`? – Alex P. Jul 18 '17 at 22:34
  • yes, you are right, I edited the question. – Rudy_FnP Jul 18 '17 at 23:04
  • Also you should check the type of returned item (directory, file,..) before creating new one inside it. May be someone has file c:\test\test1\test2" not a folder. – Alex P. Jul 18 '17 at 23:24
  • Yes you are right. However, this is a simplified example of my use case where I am sure that test[x] all stand for folders – Rudy_FnP Jul 19 '17 at 01:16
  • How do you call the function that has this bit of code? How its declaration looks like? May be your App terminates before async task is completed and so you sometime have partial creation of path. Try to make call of your function and retrieve its result before exiting from App. – Alex P. Jul 19 '17 at 12:02
  • the function signature where this piece of code is called is: task UWP_downloader::create_folders_if_required() And I am 100% sure the app is still running while this piece of code is executed. – Rudy_FnP Jul 19 '17 at 12:46
  • I am not sure of what you mean by "how do you call this function". I have an object UWP_downloader and a I call its method: `UWP_downloader^ uwpd = ref new UWP_downloader; ... uwpd->initialize(); with: bool UWP_downloader::initialize() { ... create_folders_if_required(); }` – Rudy_FnP Jul 19 '17 at 12:51
  • Try call it like this: `create_folders_if_required().get()`. – Alex P. Jul 19 '17 at 12:53
  • so it compiles, and the behaviour is different, but it is not working. With this syntax, no folder is actually created. – Rudy_FnP Jul 19 '17 at 16:47
  • 1
    I copied your function into standalone test app. And it works every time I run it (even when a part of the path is already exists, "c:\temp\test1\test2" for example). I tested two variants `create_folders_if_required()` & `create_folders_if_required().get()`, no any problem. But It silently (no any exceptions) fails only when a file with the same name is present (example: "c:\temp\test1\test2" is file not a folder). May be you should insert some debug tracing between major steps or something else that could say where it stop working well. If you find a solution please describe it. – Alex P. Jul 21 '17 at 20:58
  • 1
    I think my issue comes from the fact that the calls I do are made from the UI thread which does not support those features. I am not sure because there is no error message whatsoever. However, the function wait() from ppltasks which is suppose to do the same thing do not work on the main thread and raise an assert if I use it in my code (https://msdn.microsoft.com/en-us/library/hh749955(v=vs.120).aspx) – Rudy_FnP Jul 24 '17 at 15:45
  • Oh, you're right. I tested it in console app. – Alex P. Jul 24 '17 at 17:58
  • Found some interesting thoughts about solution but not yet tested and don'n know if it's applicable here. You should look at ["How to wait for an IAsyncAction?"](https://stackoverflow.com/questions/19917466/how-to-wait-for-an-iasyncaction). There is `WaitForAsync()` implementation that waits for a IAsyncAction completion. It needs to be modified a little to wait for `task<>`. But in general you should avoid such techniques (mixing async and blocking main thread) :). – Alex P. Jul 24 '17 at 18:18

1 Answers1

0

This works fine, on either the UI thread or a threadpool thread. I built an app doing exactly this and had no troubles at all (tested: x86 and x64, debug and release builds, VS2017 15.5.3).

The instruction after co_await will not execute until the previous one completes, as you expected.

The only possible complication that I'm aware of is – perhaps – some corruption of your subfolders list, which could happen if it's a lambda-captured variable. See this bug report for details.

Also note that if you want to programmatically do something with the newly created folder, you'll have to either make it part of the coroutine (append to the code fragment above) or co_await on the coroutine itself before acting on the folder.

David Pritchard
  • 300
  • 3
  • 5