How to await on an IAsyncOperation using C++/COM - async-await

I am accessing a WinRT API using C++ and COM.
The following code gives me results == unspecified
ComPtr<IGeolocatorStatics> statics;
RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Geolocation_Geolocator).Get(), IID_PPV_ARGS(&statics));
ComPtr<IAsyncOperation<GeolocationAccessStatus>> op;
statics->RequestAccessAsync(&op);
GeolocationAccessStatus results;
op->GetResults(&results);
Whereas I get results == allowed from adding a Sleep call.
ComPtr<IGeolocatorStatics> statics;
RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Geolocation_Geolocator).Get(), IID_PPV_ARGS(&statics));
ComPtr<IAsyncOperation<GeolocationAccessStatus>> op;
statics->RequestAccessAsync(&op);
Sleep(100);
GeolocationAccessStatus results;
op->GetResults(&results);
Obviously, I need to either await on AsyncOperation to receive a callback when it is finished. I would prefer to do the former. How do I await on a WinRT IAsyncOperation from C++ using COM?

Related

Execute a synchronous command asynchronously in Xamarin

I've built a Xamarin.Forms app that is using a DLL from a tierce app to send kind of SQL command (this is not SQL !)
Probleme is that it only provides synchronous methods and my app is then "not responding". How can I do an asynchronous method that will call the sycnhronous one and wait for its result without hanging the UI ?
I tried the following but it seems to be waitng forever like if thread was never stopping.
public async Task<ExecuteCommandResult> ExecuteMocaCommandAsync(String ps_command)
{
return await Task<ExecuteCommandResult>.Run(() =>
{
return ExecuteMocaCommand(ps_command);
}
);
}
and I'm calling it like this :
ExecuteCommandResult l_res = l_con.ExecuteMocaCommandAsync("list users where usr_id = '" + gs_UserName + "'").Result;
I'm clearly missing something and hope you can point me in the good direction.
Regards,
Yoz
The Task.Run looks good (though you can simplify it by changing Task<ExecuteCommandResult>.Run to just Task.Run). That's the proper way to push blocking work to a background thread in a UI application.
However, you can't use Result; that can deadlock. You'll need to call your method using await:
ExecuteCommandResult l_res = await l_con.ExecuteMocaCommandAsync("list users where usr_id = '" + gs_UserName + "'");

python/pyqt - Pass a CancelEvent to a C++ function

I have a WinApi function with a CancelEvent parameter but I don't know what I have to pass there?
HRESULT WINAPI DismUnmountImage(
_In_ PCWSTR MountPath,
_In_ DWORD Flags,
_In_opt_ HANDLE CancelEvent,
_In_opt_ DISM_PROGRESS_CALLBACK Progress,
_In_opt_ PVOID UserData
);
https://msdn.microsoft.com/en-us/library/windows/desktop/hh824802(v=vs.85).aspx
I'm working with python 3.6 on Windows 10. The function is working properly, the progress dialog too. I used QProgressDialog widget to display progress state, I only have to implement the CancelEvent.
The reDefinition:
from ctypes import *
import win32con, win32api
def UnmountImage(self, MountPath, Flags=DISM_DISCARD_IMAGE, CancelEvent=None, Progress=None, UserData=None):
self.hDism.DismUnmountImage.restype = HRESULT
try:
return self.hDism.DismUnmountImage(MountPath, Flags, CancelEvent, Progress, UserData)
except OSError as e:
print("DismUnmountImage failed: %s\nErrorCode: %s" % (e.strerror, e))
return self.GetLastErrorMessage()
And the pyqt part:
def canceled(self):
print("canceled")
#pyqtSlot(QVariant)
def unmount_image(self, json_data):
dism_progress_callback = dism_manager.DISM_PROGRESS_CALLBACK(self.dism_progress_callback)
data = json.loads(json_data)
self.progdialog = QProgressDialog("", "Cancel", 0, 100, None)
self.progdialog.setWindowTitle("Unmounting Image...")
self.progdialog.setModal(True)
self.progdialog.canceled.connect(self.canceled)
self.progdialog.show()
for image in data:
dism_manager.UnmountImage(MountPath=image['MountPath'], Progress=dism_progress_callback, CancelEvent=self.progdialog.winId())
I tried to pass the handle of the qtWindow but I get an error message ..can't convert parameter 3... What does the function expect? A windows handle? I really have no idea and I'm not familar with C++.
Btw: The QProgressdialog is a window with a QProgress and a QButton. When I click on the Cancel button, my def canceled(self): method is emitted and the window will be closed for a second and then the progress continues.
EDIT:
After zett42 suggestions I came up with this:
DISM_CANCEl_EVENT = CreateEvent(None, False, False, None)
And:
def canceled(self):
print("canceled")
SetEvent(dism_manager.DISM_CANCEl_EVENT)
...
for image in data:
dism_manager.UnmountImage(MountPath=image['MountPath'], Progress=dism_progress_callback, CancelEvent=dism_manager.DISM_CANCEl_EVENT)
I get this error message:
ctypes.ArgumentError: argument 3: <class 'TypeError'>: Don't know how to convert parameter 3
Do you have any idea, what I am missing?
EDIT2:
I got it:
def canceled(self):
self.progdialog.cancel()
SetEvent(self.cancel_event)
self.cancel_event = dism_manager.DISM_CANCEl_EVENT.Detach()
for image in data:
dism_manager.UnmountImage(MountPath=image['MountPath'], Progress=dism_progress_callback, CancelEvent=self.cancel_event)
The only problem I have: The cancelevent needs round about 2 seconds to be performed so that meanwhile the dism_progress_callback forces the window to popup again, although i called self.progdialog.cancel() which closes the window...hope you can follow me. Do you have any suggestions how i can control this?
Solved:
I got a final solution: I called self.progdialog.canceled.disconnect() before self.progdialog.canceled.connect(self.dism_cancel_event) to overwrite the canceled() signal and prevent the call of cancel().
The function expects the handle of an event object which can be created using the CreateEvent() C API. In Python you may call win32event.CreateEvent().
In your function def canceled(self) you should call win32event.SetEvent(hEvent) passing the handle of the event object you created for the hEvent parameter. This will request a cancellation of UnmountImage().

How can I delete a file and send it to the recycle bin in Vista/7 using IFileOperation?

According to the documentation for IFileOperation::SetOperationFlags, the FOFX_RECYCLEONDELETE flag was introduced in Windows 8.
I would like to delete files and send them to the recycle bin. How is it possible to do that using IFileOperation in Vista and Windows 7?
I know that SHFileOperation supports that functionality, but I don't want to use SHFileOperation as Microsoft are telling us to use IFileOperation in its place. Is this possible using IFileOperation, and if so, how is it to be done?
The documentation for SetOperationFlags says:
This member can be a combination of the following flags. FOF flags are defined in Shellapi.h and FOFX flags are defined in Shobjidl.h.
So you can use the exact same flag, FOF_ALLOWUNDO, that you use with SHFileOperation to direct a delete action to move to the recycle bin.
 FOFX_RECYCLEONDELETE flag was introduced in Win 8 - will it work in Vista/7?
Since FOFX_RECYCLEONDELETE was introduced in Windows 8, then it did not exist in Vista/7, so no, it will not work in those versions.
There's always SHFileOperation but I'd rather use a more up-to-date Win32 API method. Anything else to know? Any alternate ways of recycling files/folders?
SHFileOperation() is the only documented way to recycle files/folders:
When used to delete a file, SHFileOperation permanently deletes the file unless you set the FOF_ALLOWUNDO flag in the fFlags member of the SHFILEOPSTRUCT structure pointed to by lpFileOp. Setting that flag sends the file to the Recycle Bin. If you want to simply delete a file and guarantee that it is not placed in the Recycle Bin, use DeleteFile.
That same flag is available in IFileOperation, but its documented behavior is different:
Preserve undo information, if possible.
Prior to Windows Vista, operations could be undone only from the same process that performed the original operation.
In Windows Vista and later systems, the scope of the undo is a user session. Any process running in the user session can undo another operation. The undo state is held in the Explorer.exe process, and as long as that process is running, it can coordinate the undo functions.
That is why FOFX_RECYCLEONDELETE had to be introduced - to re-add the old Recycle Bin behavior that had been lost when IFileOperation was first introduced.
I have verified David Heffernan's assessment of the FOF_ALLOWUNDO flag's use with IFileOperation to send items to the recycle bin. Here's the code. Apparently SHCreateItemFromParsingName is MS's way of saying create an item from a string. This code is catered to C++ with Qt. You'll have to initialize COM first of course.
void Worker::deleteItem(QString item)
{
HRESULT hr;
IFileOperation *pfo;
wchar_t *itemWChar = new wchar_t[item.length()+1];
item.toWCharArray(itemWChar);
itemWChar[item.length()] = 0;
PCWSTR itemPCWSTR = itemWChar;
hr = CoCreateInstance(CLSID_FileOperation,
NULL,
CLSCTX_ALL,
//IID_IFileOperation,
IID_PPV_ARGS(&pfo));
if (!SUCCEEDED(hr))
{
//error handling here
return;
}
hr = pfo->SetOperationFlags(FOF_ALLOWUNDO | FOF_NOCONFIRMATION);
if (!SUCCEEDED(hr))
{
//error handling here
return;
}
IShellItem *deleteItem = NULL;
hr = SHCreateItemFromParsingName(itemPCWSTR,
NULL,
IID_PPV_ARGS(&deleteItem));
if (!SUCCEEDED(hr))
{
//error handling here
return;
}
hr = pfo->DeleteItem(deleteItem,NULL);
if (deleteItem != NULL)
{
deleteItem->Release();
}
if (!SUCCEEDED(hr))
{
//error handling here
return;
}
hr = pfo->PerformOperations();
if (!SUCCEEDED(hr))
{
//error handling here
return;
}
pfo->Release();
delete[] itemWChar;
}

http_listener cpprestsdk how to handle multiple POST requests

I have developed a client server application with casablanca cpprestskd.
Every 5 minutes a client send informations from his task manager (processes,cpu usage etc) to server via POST method.
The project should be able to manage about 100 clients.
Every time that server receives a POST request he opens an output file stream ("uploaded.txt") ,extract some initial infos from client (login,password),manage this infos, save all infos in a file with the same name of client (for example: client1.txt, client2.txt) in append mode and finally reply to client with a status code.
This is basically my POST handle code from server side:
void Server::handle_post(http_request request)
{
auto fileBuffer =
std::make_shared<Concurrency::streams::basic_ostream<uint8_t>>();
try
{
auto stream = concurrency::streams::fstream::open_ostream(
U("uploaded.txt"),
std::ios_base::out | std::ios_base::binary).then([request, fileBuffer](pplx::task<Concurrency::streams::basic_ostream<unsigned char>> Previous_task)
{
*fileBuffer = Previous_task.get();
try
{
request.body().read_to_end(fileBuffer->streambuf()).get();
}
catch (const exception&)
{
wcout << L"<exception>" << std::endl;
//return pplx::task_from_result();
}
//Previous_task.get().close();
}).then([=](pplx::task<void> Previous_task)
{
fileBuffer->close();
//Previous_task.get();
}).then([](task<void> previousTask)
{
// This continuation is run because it is value-based.
try
{
// The call to task::get rethrows the exception.
previousTask.get();
}
catch (const exception& e)
{
wcout << e.what() << endl;
}
});
//stream.get().close();
}
catch (const exception& e)
{
wcout << e.what() << endl;
}
ManageClient();
request.reply(status_codes::OK, U("Hello, World!")).then([](pplx::task<void> t) { handle_error(t); });
return;
}
Basically it works but if i try to send info from due clients at the same time sometimes it works sometimes it doen't work.
Obviously the problem if when i open "uploaded.txt" stream file.
Questions:
1)Is CASABLANCA http_listener real multitasking?how many task it's able to handle?
2)I didn't found in documentation ax example similar to mine,the only one who is approaching to mine is "Casalence120" Project but he uses Concurrency::Reader_writer_lock class (it seems a mutex method).
What can i do in order to manage multiple POST?
3)Is it possible to read some client infos before starting to open uploaded.txt?
I could open an output file stream directly with the name of the client.
4)If i lock access via mutex on uploaded.txt file, Server become sequential and i think this is not a good way to use cpprestsdk.
I'm still approaching cpprestskd so any suggestions would be helpful.
Yes, the REST sdk processes every request on a different thread
I confirm there are not many examples using the listener.
The official sample using the listener can be found here:
https://github.com/Microsoft/cpprestsdk/blob/master/Release/samples/CasaLens/casalens.cpp
I see you are working with VS. I would strongly suggest to move to VC++2015 or better VC++2017 because the most recent compiler supports co-routines.
Using co_await dramatically simplify the readability of the code.
Substantially every time you 'co_await' a function, the compiler will refactor the code in a "continuation" avoiding the penalty to freeze the threads executing the function itself. This way, you get rid of the ".then" statements.
The file problem is a different story than the REST sdk. Accessing the file system concurrently is something that you should test in a separate project. You can probably cache the first read and share the content with the other threads instead of accessing the disk every time.

Overriding PreMessageLoop, when should I call CAtlServiceModuleT::PreMessageLoop

I've got a service project in Visual Studio 2005 that was converted to a Visual Studio 2010 project. And I've noticed a problem with the PreMessageLoop function, which looks like this:
HRESULT CMyModule::PreMessageLoop (int nShowCmd)
{
HRESULT result = CAtlServiceModuleT<CMyModule,100>::PreMessageLoop(nShowCmd);
if (ERROR_SUCCESS == result)
{
ComplicatedInitialization();
_AtlModule.SetServiceStatus (SERVICE_START_PENDING);
MoreComplicatedInitialization();
_AtlModule.SetServiceStatus (SERVICE_START_PENDING);
StillMoreComplicatedInitialization();
_AtlModule.SetServiceStatus (SERVICE_START_PENDING);
EvenMoreComplicatedInitialization();
}
return result;
}
This works great in Visual C++ 2005: The Run function calls my PreMessageLoop, which calls the base-class PreMessageLoop. The complicated initialization happens when the service is in SERVICE_START_PENDING. When my PreMessageLoop returns, Run calls SetServiceStatus(SERVICE_RUNNING).
Visual C++ 2010 is different: the base-class PreMessageLoop calls SetServiceStatus(SERVICE_RUNNING). The complicated initialization happens when the service is in SERVICE_RUNNING state, which is not good (because the service looks like it is running when it is in fact still initializing).
Can I simply move the base-class PreMessageLoop call to the bottom of my PreMessageLoop call? Or is it more complicated than a simple move?
Followup
It appears that a service can go from the SERVICE_RUNNING state back to the SERVICE_START_PENDING state. Is that wise?
First of all, "if (ERROR_SUCCESS == result)" is something not quite correct, as you should be checking result against HRESULT values, that is against S_OK, S_FALSE, or using SUCCEEDED sort of macros.
Base PreMessageLoop is registering COM class objects, if your complicated initialization is not using COM instanatiation you are free to move your stuff above __super::PreMessageLoop call.
The COM Initialization codes in PreMessageLoop are causing the Error 1053.
Solution 1: Disable the COM Support.
#define _ATL_NO_COM_SUPPORT
in "stdafx.h" before all ATL related includes.
Solution 2: Override the "PreMessageLoop" and strip it from the COM Initialization codes.
HRESULT PreMessageLoop(_In_ int nShowCmd) throw()
{
if (m_bService)
{
// Make sure that service was not stoped during initialization
if (::InterlockedCompareExchange(&m_status.dwCurrentState, SERVICE_RUNNING, SERVICE_START_PENDING) == SERVICE_START_PENDING)
{
LogEvent(_T("Service started/resumed"));
::SetServiceStatus(m_hServiceStatus, &m_status);
}
}
// Start the tread(s)
_worker = new CWorkerThread();
return S_OK;
}

Resources