co_await expression needs await_ready function - c++

I have a Win32 programm, where I want to add some winRT calls. Among other things I want to open a file without a GUI interface.
I use the async file open call from the StorageFile class, because the next call needs an IStorageFile interface.
#include <roapi.h>
#include <winrt/Windows.Storage.h>
#include <winrt/Windows.Foundation.h>
void openFile()
{
using namespace winrt;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Storage;
HRESULT rtn = RoInitialize(RO_INIT_MULTITHREADED);
winrt::hstring path{ L"C:\\Users...\\mytextfile.txt"};
//wait for open the file
auto file = co_await StorageFile::GetFileFromPathAsync(path);
//IStorageFile interface needed
}
int main()
{
openFile();
return 0;
}
At the moment, the compiler complains that the co_await expression requires a suitable "await_ready" function and none was found.
I`m not sure if this is the case due to a missing header include or if "co_await" can not be used within a win32 application.
Edit:
My visual studio project setup is:
- use c++17, add cppwinrt.exe to my include directories, link against windowsapp.lib and use windows sdk version 10.0.17134.0.

The problem is that the openFile() function does not have the proper return type to handle co_await.
See the research and work that went into the answer I created for C++11 threads to update MFC application windows. SendMessage(), PostMessage() required? which contains a list of recommendations for various approaches to coroutines.
This question was about using C++/WinRT with MFC but the material also applies with WinAPI.
See as well synchronizing SDK with Windows 10 update and using WinRT with Standard C++ which contains a simple console application example using the Web Syndication async functionality to retrieve a list of URLs from an RSS feed. There are a number of links to documentation, some of which is a bit out dated now.
Addendum: Sample Console application
I created the following simple console application using Visual Studio 2017. I created the text file and then ran this in the debugger. I then renamed the text file and ran it again in the debugger and an exception was thrown since the file with that name no longer existed.
See also C++/WinRT, part of Windows SDK 17134 is not compatible with Visual Studio 15.8 Preview 3 which describes a compiler option you may need to change. I did.
// console_winrt.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
// Requires the following changes to the project properties in the C++ compiler section.
// - C++ language standard must be set to C++17
// - Add /await to the Additional options
#include "pch.h"
#pragma comment(lib, "windowsapp")
#include <winrt/Windows.Storage.h>
#include <winrt/Windows.Foundation.h>
#include <iostream>
winrt::Windows::Foundation::IAsyncAction openMyFile()
{
winrt::hstring path{ L"D:\\Users\\rickc\\mytextfile.txt" };
//wait for open the file
auto file = co_await winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(path);
//IStorageFile interface needed
auto xDate = file.DateCreated();
std::cout << "file was found " << std::endl;
}
int main()
{
// initialize the WinRT apartment.
winrt::init_apartment();
auto x = openMyFile();
// wait on the file access since that is all we are doing and we need to give it time.
x.get();
return 0;
}
I used the following properties settings.

Related

Using WRL to access WinRT, I cannot get ActivateInstance to work

I am trying to figure out how to access the WinRT API via WRL in C++, using visual studio 2022 with the latest update 17.1.2.
(Background: I've done a fair amount of old-fashioned Windows desktop programming with the Win32 API. However, I now wish to access parts of the Windows API that are supported only in WinRT, such as access to Bluetooth LE devices. Note that I am trying to avoid UWP applications, as I fear it may cause my applications to be bloated, and am not sure what needed functionality it might remove from my programs. Further, I have tried Microsoft's C++/WinRT, but was having lots of trouble at points where the Microsoft compiler was telling me there was a problem up in the generated C++ headers--not my own code. So I am now trying to work closer to the ground with WRL.)
So, starting with an example provided in MS documentation (uri winRT class, which I can get to work as they wrote it), I have tried to try use of the ActivateInstance WRL class (which is not used in their example).
It seems not to be working for me. But I am probably doing something wrong. Can anyone help?
I have pared down the code to show the precise issue:
#include <roapi.h>
#include <combaseapi.h>
#include <iostream>
#include <windows.foundation.h>
#include <windows.foundation.collections.h>
#include <wrl\wrappers\corewrappers.h>
#include <wrl\client.h>
#include <stdio.h>
using namespace ABI::Windows::Foundation;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
int dummy;
ComPtr<IUriRuntimeClassFactory> uriFactory;
ComPtr<IUriRuntimeClass> uri;
HRESULT hr, hr2;
int main()
{
// Initialize the Windows Runtime.
RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);
// Get the activation factory for the IUriRuntimeClass interface.
hr = GetActivationFactory(HStringReference(L"Windows.Foundation.Uri").Get(), &uriFactory);
hr2 = ActivateInstance (HStringReference(L"Windows.Foundation.Uri").Get(), &uri);
dummy = 1;
}
What happens is hr returns as S_OK. (Creating the factory. I don't use it here, but it is apparently a valid factory as it works when I leave in the rest of the Microsoft WRL example.)
But, what is confusing me is that hr2 is returning "E_NOTIMPl (not implemented)", and I thought it would get me a smart pointer to the uri class.
(Referencing this MS documentation for ActivateInstance:
and observing that the argument types are the same as
for GetActivationFactory
Thanks

how to call uwp class library in win32 C++ console application

I wanna call a uwp app with Uri in a win32 C++ console application.The first thing I thought is using LaunchUriAsync, but I couldn't find Windows.System.Launcher.LaunchUriAsync in win32 C++. So I wanna create a uwp class library to call LaunchUriAsync and win32 call this library. I find an example and now I can load the library sucessfully, but GetProcAddress always returns null. Not sure whether it is feasible calling uwp class library in win32 console. Pls help me out. The project is at https://github.com/vincent1000/win32CallUwpLibrary
The code is very simple:
UWP Classy Library:
namespace ExportedCodeSolution
{
public class Class1
{
[DllExport(ExportName = "callUri", CallingConvention = CallingConvention.StdCall)]
static public async void callUri()
{
Console.WriteLine("call URI start");
await Launcher.LaunchUriAsync(new Uri("www.bing.com"));
}
}
}
And Win32 Console:
using CallUriFn = void(__stdcall*) ();
int main()
{
HMODULE mod = LoadLibraryA("ExportedCodeSolution.dll");
CallUriFn fn = reinterpret_cast<CallUriFn>(GetProcAddress(mod, "callUri"));
fn();
}
Also, is any other method to call LaunchUriAsync in win32? I have searched some methods but none works for me.
The solution is trivial: Simply call Launcher.LaunchUriAsync from your console application. The easiest route is to use C++/WinRT. Assuming that you are using Visual Studio with the C++/WinRT extension installed, create a "Windows Console Application (C++/WinRT)", and replace the wizard generated code with this:
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.System.h>
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::System;
int main()
{
init_apartment();
Uri uri(L"www.bing.com");
Launcher::LaunchUriAsync(uri).get();
}
This will compile, but fail at runtime due to "www.bing.com" not being a valid URI. This needs to be replaced with a valid URI (e.g. "https://www.bing.com").

Why is a "user breakpoint" called when I run my project with imported .lib, not when code is inline?

The Situation
I am writing a wrapper library for GPIB communications for setting up specific instruments according to a clients specifications to automate some of their processes. I have to use C++ and the old '98 compiler in VC++ 6.0 running on a Windows NT machine to maintain compatibility with some other devices they use regularly.
I am trying to make a class that combines some GPIB commands into easier to remember functions, while also keeping the capability of directly communicating with the instruments. To that end, I have compiled different parts of my project into different libs and dlls, each dll being a different device that they might want to communicate with. I also made a generic dll base class from which all the specific instrument classes inherit, hopefully making the whole setup as modular as possible.
The Problem
So, with all that said, I have an issue when I try to test the different dlls/modules. I created a project to test the generic base class, added the .lib file to the project, which links to the .dll, and also #included the header file for that dll. testGeneric.cpp looks like this:
#include "GENERIC.h"
void main(void) {
GPIBInstrument hp(2); //connects to device at primary address #2
hp.write("*IDN?");
}
Super simple. To be clear, I also have the GENERIC.lib linked in the "Resource Files" folder in VC++ 6.0, and I have GENERIC.dll accessible from the path variable.
Moving on, GENERIC.h looks like this (select parts):
#ifndef GENERIC_H
#define GENERIC_H
#include <string>
#include <windows.h>
#include "decl-32.h"
#ifdef GENERIC_EXPORT
#define GENERIC_API __declspec(dllexport)
#else
#define GENERIC_API __declspec(dllimport)
#endif
...(Inline exception classes)...
class GENERIC_API GPIBInstrument {
...
public:
void write(std::string command);
...
};
#endif
Just showing the relevant methods. Then GENERIC.cpp:
#define GENERIC_EXPORT
#include "GENERIC.h"
...
void GPIBInstrument::write(std::string command) {
ibwrt (handle, &command[0u], command.length());
std::cout << command << std::endl;
if (ibsta & TIMO) {
timeoutError();
}
if (ibsta & ERR) {
error("Unable to write command to instrument: " + command);
}
}
So, looks pretty good right? No issues. Compiles fine. I try running it, and BLAM! I get this: "User breakpoint called from code at 0x77f7645c". So, then I thought, well maybe it would work if I put all the code from GENERIC.h and GENERIC.cpp into one file, and #included that file all as inline code. So I tried it, and it and it compiled nicely, and ran fine.
Question (<-AHA!... But...)
What am I doing wrong!? Something with the way I'm making the .dll? Or the .lib? Or something else entirely?
EDIT (WHY!?)
So, after a bit of debugging, I found that it was something to do with passing a string literal. So I just modified it to:
std::string command = "*IDN?";
hp.write(command);
and it worked fine. My followup question, is why? What's the difference between having a string literal passed, versus assigning that to a variable and then passing it in?
Using complex types such as std::string as a parameter at a DLL boundary is tricky. You must ensure that the exe and the DLL use the exact same instance of the library code. This requires that you build them both to use the same version of the DLL version of the runtime library.

Why does WP8.1 runtime component throw C++ exception on call to boost::filesystem::file_size()?

Windows Phone 8.x developers porting C++ with Boost code to WP8.x are aware that several Boost binary libraries contain banned Win32 calls. Thus, these Boost libraries need to be ported to WP8.x.
Steven Gates, a Microsoft engineer, ported several Boost libraries (i.e., system, chrono, date_time, smart_ptr, signals2, and thread) and wrote an excellent blog describing how he did it.
One critical Boost library he did not port is filesystem. Although I am new to WinRT and runtime components, I want to attempt to port this library to Windows Phone 8.1 (WP8.1 has less banned functionality than WP8.0, and does not require RPAL ["restricted platform allow list"] for many functions).
I began by commenting out all filesystem source code that does not compile under Windows Phone 8.1, reaching a state where I could build the filesystem library for WP8.1 ARM using the following Boost b2 command:
b2 toolset=msvc-12.0 windows-api=phone link=static architecture=arm filesystem
My overall plan is to implement the commented-out functions one at a time, testing the ported code through a minimal WP 8.1 app.
My next step was to write a minimal Windows Phone 8.1 app together with a Windows Phone Runtime Component 8.1 project, both bundled in a single solution (the runtime component will interface with the Boost library). To get them working I:
added the runtime component as a reference to the main app project
linked the Boost filesystem static library to the runtime component
added an API function within the runtime component called GetFileSize() that the app can invoke. The purpose is to exercise the boost::filesystem::file_size() function within the ported Boost library.
linked code to a UI button that, when pressed, calls into the runtime component to invoke the GetFileSize() function
The problem I have is that the call to boost::filesystem::file_size() throws an exception, and it is not obvious what the problem is.
Here is the relevant code I've written.
namespace MinimalWindowsRuntimeApp
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}
private void GetFileSize_Click(object sender, RoutedEventArgs e)
{
String filepath = "\\Phone\\Pictures\\Camera Roll\\WP_20140106_001.jpg";
var newObject = new WindowsRuntimeComponent1.Class1();
newObject.GetFileSize(filepath);
}
}
}
When I press the dedicated button on the Windows Phone screen it invokes the GetFileSize_Click() function. This code creates an instance of the WindowsRuntimeComponent1.Class1() activatable class and calls its GetFileSize () function:
// Class1.cpp
#include "pch.h"
#include "Class1.h"
#include "boost/filesystem.hpp"
using namespace WindowsRuntimeComponent1;
using namespace Platform;
Class1::Class1()
{
}
int64 Class1::GetFileSize(Platform::String ^filepath)
{
boost::filesystem::path p (filepath->Data ());
__int64 filesize = (__int64) boost::filesystem::file_size (p);
return filesize;
}
The intention is for the GetFileSize() function in the runtime component to instantiate a boost::filesystem::path object (which takes a wide-char string of the path) and invoke the boost::filesystem::file_size() function.
The problem is that the call to file_size() throws an exception, as shown in the output window:
First-chance exception at 0x774E59A3 in MinimalWindowsRuntimeApp.exe: Microsoft C++ exception: boost::filesystem::filesystem_error at memory location 0x0315E498.
Tracing into Boost with the native debugger shows the code in Boost's operations.cpp that fails:
BOOST_FILESYSTEM_DECL
boost::uintmax_t file_size(const path& p, error_code* ec)
{
. . .
# else // Windows
// assume uintmax_t is 64-bits on all Windows compilers
WIN32_FILE_ATTRIBUTE_DATA fad;
if (error(::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad)== 0,
p, ec, "boost::filesystem::file_size"))
return static_cast<boost::uintmax_t>(-1);
. . .
# endif
}
The failure occurs while calling the Win32 API GetFileAttributesExW() function. At the point of invocation, p.c_str() equals the expected "\Phone\Pictures\Camera Roll\WP_20140106_001.jpg". The function, which is supported for Windows Phone 8.1, fails and returns 0, which causes Boost's error() function to throw an exception.
My two questions are:
Why is the Win32 API GetFileAttributesExW function failing?
Is the Windows Phone file path I pass to GetFileSize (i.e., "\Phone\Pictures\Camera Roll\WP_20140106_001.jpg") the valid way to specify a file on the Windows Phone?
Many thanks in advance for any help you can give.
You need to include the drive letter ("C:\\path\\to\\file") when creating paths on Windows. Note that in a real Windows Phone app you should never hard-code the path because the user can move stuff to the SD card. You should also never store the absolute path to a file for the same reason. It's OK for your test though.
Also, you're trying to read from the Camera Roll, which you can't do directly (you can only read protected files like that through WinRT APIs). But here is a sample showing it working (replace App::App from a new, blank C++ Windows Phone project):
App::App()
{
InitializeComponent();
Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending);
auto path = std::wstring(Windows::ApplicationModel::Package::Current->InstalledLocation->Path->Data()) + L"\\Assets\\SplashScreen.scale-240.png";
std::wstringstream ss;
ss << L"Path is " << path << std::endl;
WIN32_FILE_ATTRIBUTE_DATA data{};
if (GetFileAttributesExW(path.c_str(), GET_FILEEX_INFO_LEVELS::GetFileExInfoStandard, &data))
{
ss << L"Size is " << (((LONG)data.nFileSizeHigh << sizeof(DWORD)) + (LONG)data.nFileSizeLow) << std::endl;
}
else
{
ss << L"Can't get size info: " << GetLastError() << std::endl;
}
OutputDebugString(ss.str().c_str());
}

Managed C++ Wrapper for Unmanaged Static Library with static variables hangs

The explanation of the problem is a little long-winded, please bear with me.
I have an unmanaged C++ static library that is used for financial application. It has business day conventions, swap conventions, bond conventions, etc. Most of the conventions rely on static global variables, which are initialized on first use. The library also initializes the holiday calendars on startup by running some queries against a SQL Server database using ODBC.
I have to interact with third-party software using web services. The only way to do this realistically is through C#. That isn't an issue, and I was making good progress. However, I hit a stumbling block when it became necessary to do some date calculations in C#. Since I didn't want to port all my C++ code to C#, I figured the most efficient way to achieve this would be by writing a Managed C++ Class Library DLL that is a wrapper around my unmanaged static library. Everything seems to work fine, I get no compile-time or link-time errors, and I can add the reference to the wrapper and see all the proper object definitions. However, when I try to run my application, it just hangs. I have tried playing around with a bunch of compiler setting for the wrapper DLL, to no avail. If I remove the project dependency on my unmanaged library, everything works fine. I have a strong suspicion that my liberal use of global static variables is causing issues. Is there are way to solve this problem, are at least figure out where the issue is? Example code is below.
Thanks,
Marc.
// FSAManaged.h
#pragma once
using namespace System;
//class XLDate;
namespace FSAManaged {
public ref class Futures
{
public:
static DateTime Expiry(String ^ code, DateTime date);
};
}
The implementation does not even rely on a dependency to the unmanaged static library:
// This is the main DLL file.
#include "stdafx.h"
#include "FSAManaged.h"
namespace FSAManaged
{
DateTime Futures::Expiry(String ^ code, DateTime date) {
return DateTime::Today;
}
}
For completeness' sake, here is AssemblyInfo.cpp:
#include "stdafx.h"
using namespace System;
using namespace System::Reflection;
using namespace System::Runtime::CompilerServices;
using namespace System::Runtime::InteropServices;
using namespace System::Security::Permissions;
//
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
//
[assembly:AssemblyTitleAttribute("FSAManaged")];
[assembly:AssemblyDescriptionAttribute("")];
[assembly:AssemblyConfigurationAttribute("")];
[assembly:AssemblyCompanyAttribute("?????")];
[assembly:AssemblyProductAttribute("FSAManaged")];
[assembly:AssemblyCopyrightAttribute("??????")];
[assembly:AssemblyTrademarkAttribute("")];
[assembly:AssemblyCultureAttribute("")];
//
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the value or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly:AssemblyVersionAttribute("1.0.*")];
[assembly:ComVisible(false)];
[assembly:CLSCompliantAttribute(true)];
[assembly:SecurityPermission(SecurityAction::RequestMinimum, UnmanagedCode = true)];
Use the debugger. If you test this from C# then Project + Properties, Debug, tick "Enabled unmanaged code debugging". Setting up the symbol server in Tools + Options, Debugging, Symbols is strongly recommended. Run.
When it hangs use Debug + Break All. Debug + Windows + Threads and double-click the thread that is supposed to be doing the job. Debug + Windows + Call stack to see what is going on. Post the stack trace in your question if you can't figure it out. Anything you see in the Output window and the Visual Studio status bar is relevant too.
Static C++ variables are initialized from DllMain. There are lot's of things you should not do in DllMain; triggering the load of yet another Dll being the most important one. This is easy to break if you call into other peoples libraries in from DllMain.
I suggest you make an Init function on your Dll, which you call after the dll is up and running.