I've been loading drawing svg images successfully in a UWP app built with C++/winrt but in the latest release find that the call to load the svg throws an exception.
The crash happens in an IAsync method that is hard to trace, but I've narrowed the problem down to the one line that loads the SVG.
This is normally looping to read lots of files, but very simple reduction of the problem still displays the issue:
winrt::Microsoft::Graphics::Canvas::UI::Xaml::CanvasVirtualControl resourceCreator
winrt::Windows::Storage::StorageFile nextFile = nullptr;
winrt::Microsoft::Graphics::Canvas::Svg::CanvasSvgDocument nextSvg = nullptr;
winrt::Windows::Storage::Streams::IRandomAccessStream fileStream = nullptr;
//This is called from within the lambda handling CreateResources for the CanvasVirtualControl
//The VirtualControl is provided as the resourceCreator argument
IAsyncAction loadSVGs(winrt::Microsoft::Graphics::Canvas::UI::Xaml::CanvasVirtualControl resourceCreator)
{
nextFile = m_symbol_resource_files.GetAt(i);
fileStream = co_await nextFile.OpenReadAsync();
nextSvg = co_await CanvasSvgDocument::LoadAsync(resourceCreator,fileStream);
}
The call to LoadAsync fails with
exception: winrt:hresult_invalid_argument at memory location 0x0C93F1CB
void resume()const{
->_coro_resume(_Ptr);
}
If I continue past the exception I find that the resource has in fact loaded and is usable. But if running outside Visual Studio the app will often quit at this line. Could it be that the CanvasVirtualControl is not acceptable?
Or is there a better way to load the svg from file? I haven't been able to work out the CanvasDocument's LoadFromXML, as it takes a System.String argument not available in C++/winrt and the winrt std::wstring is not acceptable as a substitute [Correction: in fact hstring will work as an argument and that can be created from std::wstring].
[Update]I have not yet created a simple demo project displaying this behavior, but I think I have a line on the cause and would like to extend my question. I've tried both the LoadFromXml and the LoadAsync methods of the CanvasSvgDocument, and the second of these used to be fine, but now both fail the same way and it seems to me that the ResourceCreator argument may be the trouble. I am creating these resources in the CreateResources handler and I pass the sender - CanvasVirtualControl - as the resourceCreator. The listed argument for both the CanvasSvgDocument calls, however, is ICanvasResourceCreator. I had thought this was a convenience and that the CanvasVirtualControl could be passed directly for that argument (and so it used to be). But perhaps this is incorrect, maybe always was and is now being noticed as incorrect? If so, how would the sender in the CreateResources handler properly be passed to the CanvasSvgDocument method?
I created a blank app to use CanvasVirtualControl to load SVG, it worked well. Can you provide a simple sample that can be reproduced? And I checked the LoadFromXML method, the parameter it needs is hstring type instead of System.String.
In addition, about loading the svg from file, do you have to use win2d to load svg? If not, you could try to use Image control by SvgImageSource to load svg, like below:
.xaml:
<Image x:Name="MyImage" Width="300" Height="200"></Image>
.cpp:
winrt::Windows::Storage::StorageFile nextFile = nullptr;
winrt::Microsoft::Graphics::Canvas::Svg::CanvasSvgDocument nextSvg = nullptr;
winrt::Windows::Storage::Streams::IRandomAccessStream fileStream = nullptr;
nextFile = co_await KnownFolders::PicturesLibrary().GetFileAsync(L"Freesample.svg");
fileStream = co_await nextFile.OpenReadAsync();
SvgImageSource sourcee = SvgImageSource();
co_await sourcee.SetSourceAsync(fileStream);
MyImage().Source(sourcee);
Related
I've ran into problem getting UI lags when this line is running:
var keys = crypt.generateKeys();
Here is the full function:
void createKeys(_) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var keys = crypt.generateKeys(); // laggy line
prefs.setString('persPriv', keys[0]);
prefs.setString('persPub', keys[1]);
prefs.setString('mesPriv', keys[2]);
prefs.setString('mesPub', keys[3]);
}
I was trying to wrap this function with Isolate.
Isolate.spawn(createKeys, null);
But I've got an error:
[VERBOSE-2:ui_dart_state.cc(199)] Unhandled Exception: Invalid argument(s): Isolate.spawn expects to be passed a static or top-level function
What is the correct way to start isolates to prevent frame drops and UI lagging?
I don't believe you can use SharedPreferences within an Isolate without support for MethodChannel / accessing platform-specific underlying OS frameworks on iOS / Android.
You would need to use FlutterIsolate or a similar package to provide that support.
chunhunghan has a good answer detailing this.
Alternatively, you could run the crypt.generateKeys() by itself in your Isolate.spawn() call and use the results after in a separate method accessing SharedPreferences. (Assuming that crypt package is also not relying on platform-specific code.)
I'm trying to port a new versio of the Isis2 library from .NET on Windows to Mono/Linux. This new code uses MemoryMappedFile objects, and I suddenly am running into issues with the Mono.Posix.Helper library. I believe that my issues would vanish if I could successfully compile and run the following test program:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.MemoryMappedFiles;
namespace foobar
{
class Program
{
static int CAPACITY = 100000;
static void Main(string[] args)
{
MemoryMappedFile mmf = MemoryMappedFile.CreateNew("test", CAPACITY);
MemoryMappedViewAccessor mva = mmf.CreateViewAccessor();
for (int n = 0; n < CAPACITY; n++)
{
byte b = (byte)(n & 0xFF);
mva.Write<byte>(n, ref b);
}
}
}
}
... at present, when I try to compile this on Mono I get a bewildering set of linker errors: it seems unable to find libMonoPosixHelper.so, although my LD_LIBRARY_PATH includes the directory containing that file, and then if I manage to get past that stage, I get "System.NotImplementedException: The requested feature is not implemented." at runtime. Yet I've looked at the Mono implementation of the CreateNew method; it seems fully implemented, and the same is true for the CreateViewAccessor method. Thus I have a sense that something is going badly wrong when linking to the Mono libraries.
Does anyone have experience with MemoryMappedFile objects under Mono? I see quite a few questions about this kind of issue here and on other sites, but all seem to be old threads...
OK, I figured at least part of this out by inspection of the Mono code implementing this API. In fact they implemented CreateNew in a way that departs pretty drastically from the .NET API, causing these methods to behave very differently from what you would expect.
For CreateNew, they actually require that the file name you specify be the name of an existing Linux file of size at least as large as the capacity you specify, and also do some other checks for access permissions (of course), exclusive access (which is at odds with sharing...) and to make sure the capacity you requested is > 0. So if you had the file previously open, or someone else does, this will fail -- in contrast to .NET, where you explicitly use memory-mapped files for sharing.
In contrast, CreateOrOpen appears to be "more or less" correctly implemented; switching to this version seems to solve the problem. To get the effect of CreateNew, do a Delete first, wrapping it in a try/catch to catch IOException if the file doesn't exist. Then use File.WriteAllBytes to create a file with your desired content. Then call CreateOrOpen. Now this sounds dumb, but it works. Obviously you can't guarantee atomicity this way (three operations rather than one), but at least you get the desired functionality.
I can live with these restrictions as it works out, but they may surprise others, and are totally different from the .NET API definition for MemoryMappedFile.
As for my linking issues, as far as I can tell there is a situation in which Mono doesn't use the LD_LIBRARY_PATH you specify correctly and hence can't find the .so file or .dll file you used. I'll post more on this if I can precisely pin down the circumstances -- on this one, I've worked around the issue by statically linking to the library.
I have looking at many threads about the exception "cannot pass a GCHandle across AppDomains" but I still don't get it....
I'm working with an RFID Reader which is driven by a DLL. I don't have source code for this DLL but only a sample to show how to use it.
The sample works great but I have to copy some code in another project to add the reader to the middleware Microsoft Biztalk.
The problem is that the process of Microsoft Biztalk works in another AppDomain. The reader handle events when a tag is read. But when I run it under Microsoft Biztalk I got this annoying exception.
I can't see any solution on how to make it work...
Here is some code that may be interesting :
// Let's connecting the result handlers.
// The reader calls a command-specific result handler if a command is done and the answer is ready to send.
// So let's tell the reader which functions should be called if a result is ready to send.
// result handler for reading EPCs synchronous
Reader.KSRWSetResultHandlerSyncGetEPCs(ResultHandlerSyncGetEPCs);
[...]
var readerErrorCode = Reader.KSRWSyncGetEPCs();
if (readerErrorCode == tKSRWReaderErrorCode.KSRW_REC_NoError)
{
// No error occurs while sending the command to the reader. Let's wait until the result handler was called.
if (ResultHandlerEvent.WaitOne(TimeSpan.FromSeconds(10)))
{
// The reader's work is done and the result handler was called. Let's check the result flag to make sure everything is ok.
if (_readerResultFlag == tKSRWResultFlag.KSRW_RF_NoError)
{
// The command was successfully processed by the reader.
// We'll display the result in the result handler.
}
else
{
// The command can't be proccessed by the reader. To know why check the result flag.
logger.error("Command \"KSRWSyncGetEPCs\" returns with error {0}", _readerResultFlag);
}
}
else
{
// We're getting no answer from the reader within 10 seconds.
logger.error("Command \"KSRWSyncGetEPCs\" timed out");
}
}
[...]
private static void ResultHandlerSyncGetEPCs(object sender, tKSRWResultFlag resultFlag, tKSRWExtendedResultFlag extendedResultFlag, tKSRWEPCListEntry[] epcList)
{
if (Reader == sender)
{
// Let's store the result flag in a global variable to get access from everywhere.
_readerResultFlag = resultFlag;
// Display all available epcs in the antenna field.
Console.ForegroundColor = ConsoleColor.White;
foreach (var resultListEntry in epcList)
{
handleTagEvent(resultListEntry);
}
// Let's set the event so that the calling process knows the command was processed by reader and the result is ready to get processed.
ResultHandlerEvent.Set();
}
}
You are having a problem with the gcroot<> helper class. It is used in the code that nobody can see, inside that DLL. It is frequently used by C++ code that was designed to interop with managed code, gcroot<> stores a reference to a managed object. The class uses the GCHandle type to add the reference. The GCHandle.ToIntPtr() method returns a pointer that the C++ code can store. The operation that fails is GCHandle.FromIntPtr(), used by the C++ code to recover the reference to the object.
There are two basic explanations for getting this exception:
It can be accurate. Which will happen when you initialized the code in the DLL from one AppDomain and use it in another. It isn't clear from the snippet where the Reader class object gets initialized so there are non-zero odds that this is the explanation. Be sure to keep it close to the code that uses the Reader class.
It can be caused by another bug, present in the C++ code inside the DLL. Unmanaged code often suffers from pointer bugs, the kind of bug that can accidentally overwrite memory. If that happens with the field that stores the gcroot<> object then nothing goes wrong for a while. Until the code tries to recover the object reference again. At that point the CLR notices that the corrupted pointer value no longer matches an actual object handle and generates this exception. This is certainly the hard kind of bug to solve since this happens in code you cannot fix and showing the programmer that worked on it a repro for the bug is very difficult, such memory corruption problems never repro well.
Chase bullet #1 first. There are decent odds that Biztalk runs your C# code in a separate AppDomain. And that the DLL gets loaded too soon, before or while the AppDomain is created. Something you can see with SysInternals' ProcMon. Create a repro of this by writing a little test program that creates an AppDomain and runs the test code. If that reproduces the crash then you'll have a very good way to demonstrate the issue to the RFID vendor and some hope that they'll use it and work on a fix.
Having a good working relationship with the RFID reader vendor to get to a resolution is going to be very important. That's never not a problem, always a good reason to go shopping elsewhere.
Is there a way to manipulate the size of a non-displayed UIView from outside the UI thread prior to adding it to a displayed view?
While working through some asynchronous iOS code, I thought I would try to have an async method build up a UIView that would be displayed later [on the UI thread]. In this case, and this appears to be the "gotcha", it was a UILabel where I want to give it a predetermined frame size derived from a StringSize call. Unfortunately, the UIView constructor that takes a RectangleF frame calls UIApplication.EnsureOnUIThread first.
// Throws UIKitThreadAccessException on Frame-setting UILabel constructor.
Task<UILabel> getView = Task.Factory.StartNew(() => {
//... Do some async fun (e.g., call web service for some data for someNSString)
SizeF requiredStringSize = someNSString.StringSize(someFont, new SizeF(maxWidth, float.MaxValue), UILineBreakMode.WordWrap);
RectangleF someViewFrame = new RectangleF(PointF.Empty, requiredStringSize)
return new UILabel(someViewFrame);
});
Since I don't really need to set a valid location at the point of this task execution, I figured I could avoid setting the frame in the constructor and set the size afterwards. Unfortunately, you only seem to be able to set size by modifying UIView.Frame as a whole. While the parameter-less constructor does not make this UI thread call, as soon as I try to set the Frame to the size needed, the UIView.Frame accessor does and it blows up.
// Also throws UIKitThreadAccessException, this time when setting the Frame directly.
Task<UILabel> getView = Task.Factory.StartNew(() => {
//...do all the above stuff...
UIView someView = new UILabel();
someView.Frame = new RectangleF(someView.Frame.Location, requiredStringSize);
});
I've already decided to make my code more specific to the case at hand and use a Task<string> instead, letting the displaying code (run on the UI thread) handle the view creation, but it would be nice to know if this is possible since it would make the code I am writing more extensible.
UIKit is not designed to be used outside of the main thread.
I've seen some bizarre behaviour creep in when this rule is ignored, so I strongly advise against this.
I'm having trouble finding out how to run a method in a seperate thread in C++ (using Visual C++ 2008), I've tried a number of ways to do this but none of them so far have been successful.
I'm very new to C++ but a fairly experienced programmer in Java, but have been given a task to fix some bugs in an old C++ application. The program uses an object called 'Mpeg' to control packetising and depackitising an Mpeg file. After setting up an Mpeg object properly, mpeg.Depacketise needs to be called, which then runs the method DepacketiseInputFile().
I've tried to make DepacketiseInputFile() run in a seperate thread by both using _beginthread and the System::Threading::Thread object using
Thread^ th = gcnew Thread(gcnew ThreadStart(DepacketiseInputFile));
however this returns the errors
using &Mpeg::Depacketise gives the error
when using _beginthread the code I tried was
However with this I constantly had trouble getting the arguments correct, with errors like
cropping up.
Is there any simple way to do this that anyone can reccomend? I've spent a few days playing around with this but seem to be getting nowhere :(
Any help would be greatly appreciated.
Cheers.
What kind of type is Mpeg? What kind of method is DepacketiseInputFile?
If it's a regular unmanaged, C++ class, then use _beginthread, but you have to make DepacketiseInputFile a static. It cannot take a member function.
Also, don't call DepacketiseInputFile with DepacketiseInputFile(), pass it in with
&Mpeg::DepacketiseInputFile
You should use the void* you get to pass it to pass in a pointer to the Mpeg object (and then cast it back).
If you want to use ThreadStart, then Mpeg needs to be a managed class.
EDIT: If you want to make DepacketiseInputFile, but it needs to access the object, then you use the void* argument to pass in a pointer.
So in the .h:
void DepacketiseInputFileMember();
static void DepacketiseInputFile(void *thisObj);
Your code goes in DepacketiseInputFileMember(), and write DepacketiseInputFile like this:
void Mpeg::DepacketiseInputFile(void *thisObj)
{
Mpeg* mpeg = reinterpret_cast<Mpeg*>(thisObj);
mpeg->DepacketiseInputFileMember();
}
When you call _beginthread, use this
_beginnthread(&Mpeg::DepacketiseInputFile, (unsigned)0, anMpegObjectPointer);
where anMpegObjectPointer is a pointer to an object of type Mpeg. You have to make sure the lifetime of the object is longer than it would be needed in the thread.
Forgive my syntax, I am writing this in a textarea, not Visual Studio
Change
_beginthread(DepacketiseInputFile(), (unsigned)0, (void *)NULL);
to
_beginthread(DepacketiseInputFile, (unsigned)0, (void *)NULL);
You wanna pass the address of the function to run (DepacketiseInputFile) and not its return value of that function (which is what you get from DepacketiseInputFile()).
I'm assuming DepacketiseInputFile is declared as void DepacketiseInputFile(void*), and is not a non-static member function of some class. Otherwise, the types won't match even when you do remove the brackets.