Send HttpRequestMessage in C++, Windows API UWP - c++

This is not C++/CLI. This is UWP C++/CX
I am trying to send an HttpRequestMessage outside of a managed class in C++. I looked at the UWP samples, but their requests occur inside of a managed class.
All I want to do is send the request, and then have a callback function. I don't need fancy async/await patterns. This is looking to be a lot more difficult than it should be.
EDIT: I have gotten it to work, but the error handling is atrocious. The extra error handling code from the UWP HttpClient example was not compiling.
client = ref new Windows::Web::Http::HttpClient();
client->DefaultRequestHeaders->UserAgent->Append(ref new Windows::Web::Http::Headers::HttpProductInfoHeaderValue("Windows", "10"));
cancellation_token_source cancellationTokenSource = cancellation_token_source();
create_task(client->SendRequestAsync(message)).then([=](Windows::Web::Http::HttpResponseMessage^ response)
{
auto operation = response->Content->ReadAsBufferAsync();
auto task = create_task(operation);
if (task.wait() == task_status::completed)
{
webResponse->statusCode = (int)response->StatusCode;
auto buffer = task.get();
size_t length = buffer->Length;
if (length > 0)
{
Array<byte>^ array = nullptr;
CryptographicBuffer::CopyToByteArray(buffer, &array);
webResponse->contentLength = array->Length;
webResponse->data = (byte*)malloc(webResponse->contentLength);
memcpy(webResponse->data, array->Data, webResponse->contentLength);
delete array;
}
for each(IKeyValuePair<String^, String^>^ pair in response->Headers)
{
std::string key = PlatformStringToString(pair->Key);
std::string value = PlatformStringToString(pair->Value);
if (key == "Content-Type" && false)
{
// Should have this for completeness, but do we really care?
}
else
{
Web::WebHeader *header = new Web::WebHeader(key.c_str(), value.c_str());
webResponse->AddHeader(header);
}
}
if (request->receiveDoneCallback)
request->receiveDoneCallback(webResponse, request->userPtr);
}
else
abort();
delete request;
delete response;
});

Related

Cannot get an asynchronous operation Result (Windows::Foundation::IAsyncOperation interface) in C++ WinRT

I'm a little bit desperate trying to get the result of a winrt asynchronous method with Windows::Foundation::IAsyncOperation interface. The project is a Visual Studio Community 2017 c++ project with winRT extension enabled.
I've tried using std::future / co_await functions and also task method but the call to GetResults() generated always "call at unexpected time" exception.
With the following code I don't get the exception but GetResults() returns nullptr. I have tried also to declare async_op as a shared_ptr auto async_op = std::make_shared<Windows::Foundation::IAsyncOperation<Windows::Devices::Bluetooth::BluetoothLEDevice^> ^> and access to it with *async_op inside the Handler code, but I get the same result.
Any ideas will be welcome.
Thanks in advance.
void BleEnumeration::PerformConnectDevice(std::string* bleDevId)
{
std::wstring bleDevId_w_str = std::wstring((*bleDevId).begin(), (*bleDevId).end());
const wchar_t* bleDevId_w_char = bleDevId_w_str.c_str();
Platform::String^ bleDevId_refStr = ref new Platform::String(bleDevId_w_char);
auto async_op = Windows::Devices::Bluetooth::BluetoothLEDevice::FromIdAsync(bleDevId_refStr);
async_op->Completed = ref new Windows::Foundation::AsyncOperationCompletedHandler<Windows::Devices::Bluetooth::BluetoothLEDevice^>(
[async_op] (Windows::Foundation::IAsyncOperation< Windows::Devices::Bluetooth::BluetoothLEDevice^ >^ operation, Windows::Foundation::AsyncStatus status)
{
if (async_op->Status == Windows::Foundation::AsyncStatus::Completed)
{
auto bleDevTest = async_op->GetResults();
}
});
}
I made it work:
Windows::Devices::Bluetooth::BluetoothLEDevice^ BleEnumeration::getBleDevice(Windows::Foundation::IAsyncOperation<Windows::Devices::Bluetooth::BluetoothLEDevice^>^ async)
{
if ((async)->Status != Windows::Foundation::AsyncStatus::Completed)
{
HANDLE signal = CreateEvent(nullptr, true, false, nullptr);
(async)->Completed = ref new Windows::Foundation::AsyncOperationCompletedHandler<Windows::Devices::Bluetooth::BluetoothLEDevice^>(
[&signal](Windows::Foundation::IAsyncOperation< Windows::Devices::Bluetooth::BluetoothLEDevice^ >^ operation, Windows::Foundation::AsyncStatus status)
{
SetEvent(signal);
});
WaitForSingleObject(signal, INFINITE);
}
Windows::Devices::Bluetooth::BluetoothLEDevice^ device = async->GetResults();
return device;
}
bool BleEnumeration::PerformConnectDevice(std::string* bleDevId)
{
bool success = false;
Windows::Devices::Bluetooth::BluetoothLEDevice^ bleDevTest = nullptr;
std::wstring bleDevId_w_str = std::wstring((*bleDevId).begin(), (*bleDevId).end());
const wchar_t* bleDevId_w_char = bleDevId_w_str.c_str();
Platform::String^ bleDevId_refStr = ref new Platform::String(bleDevId_w_char);
Windows::Foundation::IAsyncOperation<Windows::Devices::Bluetooth::BluetoothLEDevice^>^ asyncOp = Windows::Devices::Bluetooth::BluetoothLEDevice::FromIdAsync(bleDevId_refStr);
bleDevTest = getBleDevice(asyncOp);
if (bleDevTest != nullptr)
{
success = true;
}
return success;
}
And, the reason why GetResults() gave nullptr was this: Enable capability in appxmanifest
All needed capabilities must be enabled in Visual Studio project Package.appxmanifest file, in my case: "Bluetooth". I noticed I was getting error: onecoreuap\drivers\wdm\bluetooth\user\winrt\device\bluetoothledevice.cpp(728)\Windows.Devices.Bluetooth.dll!00007FFC1601AE2F: (caller: 00007FFC1602081A) Exception(1) tid(212c) 80070005 Access is denied.

How to break dependency on StreamReader's readLine() method in microsoft fakes unit testing?

Here is my code in one of the method which I want to test:
using (var sr = new StreamReader(myFile))
{
string line;
while ((line = sr.ReadLine()) != null)
{
if (line.Equals("completed"))
{
continue; //here it is getting called infinite times
}
if(line.Equals("processed"))
{
break;
}
}
}
In my test method I have written below code with the help of shim:
ShimStreamReader.ConstructorString = delegate (StreamReader #this, string #string)
{
var reader = new ShimStreamReader(#this);
reader.ReadLine = () =>
{
return "completed";
};
};
Now I dont want to pass the file. Instead I want to pass the stream of characters or string.
Above test code is calling and breaking the dependency of new StreamReader(myFile) as expected and entering into while loop.
As soon as it is entering it in while loop, sr.ReadLine() is returning "completed" all the time. So I'm stuck here. How would I stop here or how would I write the input string so that as soon as my first call return completed in second call of sr.ReadLine() it should return null, and then breaks the loop?
You're more into a general coding question here rather than fakes. All you need to do is add a flag and set it when you're ready to end the input. This is the code I used
private bool _lineSent = false;
[TestMethod]
public void ReaderTest()
{
using (ShimsContext.Create())
{
ShimStreamReader.ConstructorString = (reader, s) =>
{
ShimStreamReader shimReader = new ShimStreamReader(reader);
shimReader.ReadLine = () =>
{
if (!_lineSent)
{
_lineSent = true;
return "completed";
}
else
{
return null;
}
};
};
ClassToTest testInstance = new ClassToTest();
testInstance.ReadStream();
}
}
By the way, depending on your level and what you are trying to learn, you might want to look into dependency injection and using stubs rather then shims. Shims are handy and nice, but for new development and code under your control, try to use stubs.

winrt c++/cx concurrency access violation exception

What I'm trying to do is check for the existence of a file in the local folder and then copy it there if it isn't found (the file was previously added to the project as an asset).
Here is the code:
Windows::Storage::StorageFile^ MainPage::GetCustomFileAsync(Platform::String^ fileName)
{
using Windows::Storage::StorageFile;
using Windows::Storage::StorageFolder;
auto localFolder = Windows::Storage::ApplicationData::Current->LocalFolder;
auto localTask = concurrency::create_task(localFolder->GetFileAsync(fileName));
StorageFile^ retVal = nullptr;
localTask.then([&](StorageFile^ t){
retVal = t;
}).then([](concurrency::task<void> t)
{
try
{
t.get();
OutputDebugString(L"Found\n");
}
catch (Platform::COMException^ e)
{
OutputDebugString(e->Message->Data());
}
}).wait();
return retVal;
}
StorageFile^ fileVar;
if ((fileVar = this->GetCustomFileAsync("somefile.txt")) == nullptr)
{
String^ path = Windows::ApplicationModel::Package::Current->InstalledLocation->Path + "\\Assets";
concurrency::create_task(Windows::Storage::StorageFolder::GetFolderFromPathAsync(path)).then([](StorageFolder^ folder){
return (folder->GetFileAsync("somefile.txt"));
}).then([](StorageFile^ file){
return (file->CopyAsync(Windows::Storage::ApplicationData::Current->LocalFolder));
}).then([&](StorageFile^ file){
fileVar = file;
OutputDebugString(file->DisplayName->Data());
});
}
What happens is that I get an access violation exception at the point where "file" is being assigned to "fileVar" (because of cross-thread access perhaps?). How to fix this?
Edit: I can't do all the processing there because the file will be accessed many times. In short I need to know when it has been successfully copied and get a handle to it. Here is the code that works
Windows::Storage::StorageFile^ GetFile(Platform::String^ fileName)
{
using Windows::Storage::StorageFile;
using Windows::Storage::StorageFolder;
using Windows::Foundation::AsyncOperationCompletedHandler;
using Windows::Foundation::AsyncStatus;
using Windows::Foundation::IAsyncOperation;
using Platform::String;
auto localFolder = Windows::Storage::ApplicationData::Current->LocalFolder;
bool completed = false;
StorageFile^ retVal = nullptr;
localFolder->GetFileAsync(fileName)->Completed = ref new AsyncOperationCompletedHandler<StorageFile^>([&completed, &retVal, &fileName](IAsyncOperation<StorageFile^>^ fileOperation, AsyncStatus status)
{
if (status == AsyncStatus::Error)
{
String^ path = Windows::ApplicationModel::Package::Current->InstalledLocation->Path + "\\Assets";
Windows::Storage::StorageFolder::GetFolderFromPathAsync(path)->Completed = ref new AsyncOperationCompletedHandler<Windows::Storage::StorageFolder^>(
[&completed, &retVal, &fileName](IAsyncOperation<Windows::Storage::StorageFolder^>^ folderOperation, AsyncStatus status)->void{
auto assetFolder = folderOperation->GetResults();
assetFolder->GetFileAsync(fileName)->Completed = ref new AsyncOperationCompletedHandler<Windows::Storage::StorageFile^>([&completed, &retVal, &fileName](IAsyncOperation<Windows::Storage::StorageFile^>^ fileOperation, AsyncStatus status)->void{
auto file = fileOperation->GetResults();
file->CopyAsync(Windows::Storage::ApplicationData::Current->LocalFolder)->Completed = ref new AsyncOperationCompletedHandler<Windows::Storage::StorageFile^>
([&completed, &retVal, &fileName](IAsyncOperation<Windows::Storage::StorageFile^>^ fileOperation, AsyncStatus status)->void {
retVal = fileOperation->GetResults();
completed = true;
});
});
});
}
else
{
retVal = fileOperation->GetResults();
completed = true;
}
});
while (completed == false);
return retVal;
}
Rather than passing a delegate as an argument and returning void, make your method return task<StorageFile^> and then the caller can do a .then() to continue working once the operation has succeeded.
Or if this is exposed as a public WinRT method (not an internal / private C++ method) then use IAsyncOperation<StorageFile^>^ as the return type, and wrap the whole thing in create_async():
IAsyncOperation<StorageFile^>^ DoStuff(params)
{
return concurrency::create_async([params]
{
// function body goes here
});
}
Here's a solution I put together. Two things that are important to know:
When executing an asynchronous operation using concurrency::create_task the async operation(s) can still be executing when the parent function returns. So the captured variables MUST outlive the context of the parent function. Which obviously won't happen if they are being passed by reference. It took a while to realize this.
WinRT imposes certain restrictions on the concurrency runtime. Calling concurrency::task::get() or concurrency::task::wait() will throw an exception in an STA thread, unless the call is in a task continuation.
More information in this post:
http://social.msdn.microsoft.com/Forums/windowsapps/en-US/ae54980b-41ce-4337-a059-2213b549be4b/concurrencyinvalidoperation-when-calling-tasktget?forum=winappswithnativecode
In that case how to know when the function has finished doing it's job? I opted to pass in a callback (AKA delegate).
delegate void FileOperation(Windows::Storage::StorageFile^ file);
void GetFileConcurrency(Platform::String^ fileName, FileOperation^ fileOp)
{
using Windows::Storage::StorageFile;
using Windows::Storage::StorageFolder;
using Platform::String;
auto localFolder = Windows::Storage::ApplicationData::Current->LocalFolder;
String^ assetFolderPath = Windows::ApplicationModel::Package::Current->InstalledLocation->Path + "\\Assets";
auto localFolderTask = concurrency::create_task(localFolder->GetFileAsync(fileName));
localFolderTask.then([localFolder, assetFolderPath, fileName, fileOp](concurrency::task<StorageFile^> theTask){
try
{
StorageFile^ theFile = theTask.get();
fileOp(theFile);
}
catch (Platform::Exception^ e)
{
OutputDebugString(e->Message->Data());
auto assetFolderTask = concurrency::create_task(StorageFolder::GetFolderFromPathAsync(assetFolderPath));
assetFolderTask.then([localFolder, assetFolderPath, fileName, fileOp](StorageFolder^ assetFolder){
auto assetFileTask = concurrency::create_task(assetFolder->GetFileAsync(fileName));
assetFileTask.then([localFolder, assetFolderPath, fileName, fileOp](StorageFile^ file){
auto copyFileTask = concurrency::create_task(file->CopyAsync(localFolder));
copyFileTask.then([localFolder, assetFolderPath, fileName, fileOp](StorageFile^ file){
OutputDebugString(file->Path->Data());
fileOp(file);
});
});
});
}
});
}

Getting org.xmlpull.v1.XmlPullParserException for SOAP connection in BlackBerry

I am using ksoap2.jar in my application for webservice call.
While conneting, to the server it is giving the below error when i am testing using Wi-fi or simulator:
org.xmlpull.v1.XmlPullParserException: unexpected type (position:END_DOCUMENT null#1:0 in java.io.InputStreamReader#6111a1f1)
And when i am testing using SIM Card, it is throwing this error: java.io.InterruptedIOException: Local connection timed out after ~ 120000
I have written the below code for this webservice connection:
SoapObject rpc = new SoapObject(serviceNamespace, methodName);
rpc.addProperty("UserID", "1");
rpc.addProperty("UserName", "xyz");
rpc.addProperty("ContactNo", "9014567890");
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.bodyOut = rpc;
envelope.dotNet = true;
envelope.encodingStyle = SoapSerializationEnvelope.ENC;
HttpTransport ht = new HttpTransport(serviceUrl + getConnectionString().trim());
ht.debug = true;
System.out.println("debug true ------- ");
ht.setXmlVersionTag(" version=\"1.0\" encoding=\"UTF-8\"?>");
SoapObject response = null;
try
{
ht.call(soapAction, envelope);
response = (SoapObject )envelope.getResponse();
String resultbody = response.getProperty("updateUserDetailResult").toString();
}
catch(org.xmlpull.v1.XmlPullParserException ex2){
resultLbl.setText(ex2.toString());
}
catch(Exception ex){
String bah = ex.toString();
resultLbl.setText(bah);
}
/**
* Looks through the phone's service book for a carrier provided BIBS network
*
* #return The uid used to connect to that network.
*/
private static String getCarrierBIBSUid()
{
net.rim.device.api.servicebook.ServiceRecord[] records = ServiceBook.getSB().getRecords();
int currentRecord;
for (currentRecord = 0; currentRecord < records.length; currentRecord++)
{
if (records[currentRecord].getCid().toLowerCase().equals("ippp")) {
if (records[currentRecord].getName().toLowerCase().indexOf("bibs") >= 0) {
return records[currentRecord].getUid();
}
}
}
return null;
}
/**
* Getting the connection string based on the connection
* #return
*/
public static String getConnectionString()
{
String connectionString = null;
// Wifi is the preferred transmission method
if (WLANInfo.getWLANState() == WLANInfo.WLAN_STATE_CONNECTED)
{
connectionString = ";interface=wifi";
}
// Is the carrier network the only way to connect?
else if ((CoverageInfo.getCoverageStatus() & CoverageInfo.COVERAGE_DIRECT) == CoverageInfo.COVERAGE_DIRECT)
{
String carrierUid = getCarrierBIBSUid();
if (carrierUid == null)
{
// Has carrier coverage, but not BIBS. So use the carrier's TCP
// network
connectionString = ";deviceside=true";
}
else
{
// otherwise, use the Uid to construct a valid carrier BIBS
// request
connectionString = ";deviceside=false;connectionUID=" + carrierUid + ";ConnectionType=";
}
}
// Check for an MDS connection instead (BlackBerry Enterprise Server)
else if ((CoverageInfo.getCoverageStatus() & CoverageInfo.COVERAGE_MDS) == CoverageInfo.COVERAGE_MDS)
{
connectionString = ";deviceside=false";
}
// If there is no connection available abort to avoid bugging the user
// unnecssarily.
else if (CoverageInfo.getCoverageStatus() == CoverageInfo.COVERAGE_NONE)
{
}
// In theory, all bases are covered so this shouldn't be reachable.
else
{
connectionString = ";deviceside=true";
}
return connectionString;
}
I am using the preverified ksoap jar file(ksoap2-j2me-core-prev-2.1.2.jar).
I am not getting exactly where it is going wrong. I have searched in the forum but did not get the proper solution.
Thanks.

TTS over web-service in compressed format

I have developed TTS engine in .NET. Now I want to expose it over web.
I have used the base64 string encoding to transfer the WAV format, but it is slow when I pass longer text.
Now I'm considering to build some MP3 streaming (maybe with NAudio) where I will convert the WAV formated MemoryStream into MP3 stream and pass it to the client. Does anyone has some experience with this?
Does anyone has experience how to convert WAV MemoryStream with NAudio to MP3 MemoryStream?
public class MP3StreamingPanel2 : UserControl
{
enum StreamingPlaybackState
{
Stopped,
Playing,
Buffering,
Paused
}
private BufferedWaveProvider bufferedWaveProvider;
private IWavePlayer waveOut;
private volatile StreamingPlaybackState playbackState;
private volatile bool fullyDownloaded;
private HttpWebRequest webRequest;
public void StreamMP32(string url)
{
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
SettingsSection section = (SettingsSection)config.GetSection("system.net/settings");
section.HttpWebRequest.UseUnsafeHeaderParsing = true;
config.Save();
this.fullyDownloaded = false;
webRequest = (HttpWebRequest)WebRequest.Create(url);
int metaInt = 0; // blocksize of mp3 data
webRequest.Headers.Clear();
webRequest.Headers.Add("GET", "/ HTTP/1.0");
// needed to receive metadata informations
webRequest.Headers.Add("Icy-MetaData", "1");
webRequest.UserAgent = "WinampMPEG/5.09";
HttpWebResponse resp = null;
try
{
resp = (HttpWebResponse)webRequest.GetResponse();
}
catch (WebException e)
{
if (e.Status != WebExceptionStatus.RequestCanceled)
{
//ShowError(e.Message);
}
return;
}
byte[] buffer = new byte[16384 * 4]; // needs to be big enough to hold a decompressed frame
try
{
// read blocksize to find metadata block
metaInt = Convert.ToInt32(resp.GetResponseHeader("icy-metaint"));
}
catch
{
}
IMp3FrameDecompressor decompressor = null;
try
{
using (var responseStream = resp.GetResponseStream())
{
var readFullyStream = new ReadFullyStream(responseStream);
readFullyStream.metaInt = metaInt;
do
{
if (bufferedWaveProvider != null && bufferedWaveProvider.BufferLength - bufferedWaveProvider.BufferedBytes < bufferedWaveProvider.WaveFormat.AverageBytesPerSecond / 4)
{
Debug.WriteLine("Buffer getting full, taking a break");
Thread.Sleep(500);
}
else
{
Mp3Frame frame = null;
try
{
frame = Mp3Frame.LoadFromStream(readFullyStream, true);
}
catch (EndOfStreamException)
{
this.fullyDownloaded = true;
// reached the end of the MP3 file / stream
break;
}
catch (WebException)
{
// probably we have aborted download from the GUI thread
break;
}
if (decompressor == null)
{
// don't think these details matter too much - just help ACM select the right codec
// however, the buffered provider doesn't know what sample rate it is working at
// until we have a frame
WaveFormat waveFormat = new Mp3WaveFormat(frame.SampleRate, frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frame.FrameLength, frame.BitRate);
decompressor = new AcmMp3FrameDecompressor(waveFormat);
this.bufferedWaveProvider = new BufferedWaveProvider(decompressor.OutputFormat);
this.bufferedWaveProvider.BufferDuration = TimeSpan.FromSeconds(20); // allow us to get well ahead of ourselves
//this.bufferedWaveProvider.BufferedDuration = 250;
}
int decompressed = decompressor.DecompressFrame(frame, buffer, 0);
//Debug.WriteLine(String.Format("Decompressed a frame {0}", decompressed));
bufferedWaveProvider.AddSamples(buffer, 0, decompressed);
}
} while (playbackState != StreamingPlaybackState.Stopped);
Debug.WriteLine("Exiting");
// was doing this in a finally block, but for some reason
// we are hanging on response stream .Dispose so never get there
decompressor.Dispose();
}
}
finally
{
if (decompressor != null)
{
decompressor.Dispose();
}
}
}
}
NAudio does not include an MP3 encoder. When I need to encode MP3 I use lame.exe. If you don't want to go via a file, lame.exe allows you to read from stdin and write to stdout, so if you redirect standard in and out on the process you can convert on the fly.