WebView issues on migrating Awesomium 1.6.6 to 1.7.1 - awesomium

I'm migrating code from Awesomium 1.6.6 to 1.7.1, which loads a url and saves it as a png.
Wondering about a few issues:
Does setting WebView.Source implicitly load the page (Apparently does, judging from the provided sample)?
WebView.ResourceRequest was used to set the request to post and push some form data into it. In the 1.7.1 way I attach a ResourceInterceptor to WebCore and raise an event to be caught by WebViews and screened against the ProcessId. But, is there any way to attach a ResourceInterceptor to a WebView to make this simpler?
WebView.RequestScrollData() and WebView.ScrollDataReceived were used to get width/height data for resize. Is that supposed to be taken from WebView.Height/Width now? and, when is it guaranteed to be set (i.e. on LoadingFrameComplete, etc)?
How can I detect that a resize has ended, i.e. the former WebView.ResizeComplete event?

Well, this is embarrassing, I'm kinda talking to myself...
So I figured out the answers for the last two issues:
Getting the size should be done through a JavaScript code executed from the WebView's LoadingFrameComplete event:
WebView _view;
_view.LoadingFrameComplete += LoadingFrameCompleteHandler;
private void LoadingFrameCompleteHandler(object sender, FrameEventArgs e)
{
if (e.IsMainFrame)
{
var view = (WebView)sender;
var js = "(function() { some js code to return size }) ();";
var size = view.ExecuteJavascriptWithResult(js);
if (size != JSValue.Null && size != JSValue.Undefined)
{
var values = (JSValue[])size;
int width = (int)values[0];
int height = (int)values[1];
view.Resize(width, height);
}
}
}
This is how you catch the resize:
WebView view;
((BitmapSurface)view.Surface).Resized += YourResizeHandler;

Related

Cocos2d-x Multithreading sceanrio crashes the game

my scenario is simple:i made a game using cocos2d-x and i want to download images (FB and Google play) for multi player users and show them once the download is done as texture for a button.
in ideal world, things work as expected.
things get tricky when those buttons got deleted before the download is done.
so the callback function is in weird state and then i get signal 11 (SIGSEGV), code 1 (SEGV_MAPERR)
and the app crashes
This is how i implmented it
I have a Layout class called PlayerIcon. the cpp looks like this
void PlayerIcon::setPlayer(string userName, string displayName, string avatarUrl){
try {
//some code here
downloadAvatar(_userName, _avatarUrl);
//some code here
}
catch(... ){
}
}
void PlayerIcon::downloadAvatar(std::string _avatarFilePath,std::string url) {
if(!isFileExist(_avatarFilePath)) {
try {
auto downloader = new Downloader();
downloader->onFileTaskSuccess=CC_CALLBACK_1(PlayerIcon::on_download_success,this);
downloader->onTaskError=[&](const network::DownloadTask& task,int errorCode,
int errorCodeInternal,
const std::string& errorStr){
log("error while saving image");
};
downloader->createDownloadFileTask(url,_avatarFilePath,_avatarFilePath);
}
catch (exception e)
{
log("error while saving image: test");
}
} else {
//set texture for button
}
}
void PlayerIcon::on_download_success(const network::DownloadTask& task){
_isDownloading = false;
Director::getInstance()->getScheduler()-> performFunctionInCocosThread(CC_CALLBACK_0(PlayerIcon::reload_avatar,this));
}
void PlayerIcon::reload_avatar(){
try {
// setting texture in UI thread
}
catch (...) {
log("error updating avatar");
}
}
As i said, things works fine until PlayerIcon is deleted before the download is done.
i dont know what happens when the call back of the download task point to a method of un object that s deleted (or flagged for deletion).
i looked in the downloader implementation and it doesn't provide any cancellation mechanism
and i'm not sure how to handle this
Also, is it normal to have 10% crash rate on google console for a cocos2dx game
any help is really appreciated
Do you delete de Downloader in de destructor of the PlayerIcon?
there is a destroy in the apple implementation witch is trigered by the destructor.
-(void)doDestroy
{
// cancel all download task
NSEnumerator * enumeratorKey = [self.taskDict keyEnumerator];
for (NSURLSessionDownloadTask *task in enumeratorKey)
{
....
DownloaderApple::~DownloaderApple()
{
DeclareDownloaderImplVar;
[impl doDestroy];
DLLOG("Destruct DownloaderApple %p", this);
}
In the demo code of cocos2d-x: DownloaderTest.cpp they use:
std::unique_ptr<network::Downloader> downloader;
downloader.reset(new cocos2d::network::Downloader());
instead of:
auto downloader = new Downloader();
It looks like you are building this network code as part of your scene tree. If you do a replaceScene/popScene...() call, while the async network software is running in the background, this will cause the callback to disappear (the scene will be deleted from the scene-stack) and you will get a SEGFAULT from this.
If this is the way you've coded it, then you might want to extract the network code to a global object (singleton) where you queue the requests and then grab them off the internet saving the results in the global-object's output queue (or their name and location) and then let the scene code check to see if the avatar has been received yet by inquiring on the global-object and loading the avatar sprite at this point.
Note, this may be an intermittent problem which depends on the speed of your machine and the network so it may not be triggered consistently.
Another solution ...
Or you could just set your function pointers to nullptr in your PlayerIcon::~PlayerIcon() (destructor):
downloader->setOnFileTaskSuccess(nullptr);
downloader->setOnTaskProgress(nullptr);
Then there will be no attempt to call your callback functions and the SEGFAULT will be avoided (Hopefully).

SHGetFileInfo doesn't return correct handle to icon

I'm using SHGetFileInfo function for getting icons for folders and different file types. According to MSDN call of this function should be done from background thread and before call Component Object Model (COM) must be initialized with CoInitialize or OleInitialize.
My code looks like this:
public void SetHlinkImage(string path)
{
Shell32.OleInitialize(IntPtr.Zero);
Task task = Task.Factory.StartNew(() => { LoadIcons(path); });
}
private void LoadIcons(string path)
{
image = GetHlinkImage(path);
if (OwnerControl.InvokeRequired)
layout.ModuleControl.BeginInvoke((MethodInvoker)delegate ()
{
Shell32.OleUninitialize();
});
}
public Icon GetHlinkImage(string path)
{
uint flags = Shell32.SHGFI_ICON | Shell32.SHGFI_ATTRIBUTES | Shell32.SHGFI_SMALLICON;
Shell32.SHFILEINFO shfi = new Shell32.SHFILEINFO();
IntPtr result = Shell32.SHGetFileInfo(path,
Shell32.FILE_ATTRIBUTE_DIRECTORY,
ref shfi,
(uint)Marshal.SizeOf(shfi),
flags);
Icon icon = (Icon)Icon.FromHandle(shfi.hIcon).Clone();
WinApi.DestroyIcon(shfi.hIcon); // cleanup
return icon;
}
Mostly the problem appears after first call of the code and as result I get an exception when I tried to create Icon from icon handle:
System.ArgumentException: Win32 handle that was passed to Icon is not
valid or is the wrong type
And further calls of the code work without problems.
Actually behaviour also somehow depends on the test system. It is hardly possible to reproduce this issue on Windows10 systems but on Windows 7 it happens quite often.
Has anyone experienced this problem?
From comment of Hans Passant:
Calling OleInitialize() is pointless, the CLR already initializes COM before it starts a thread. And it failed, something you cannot see because you are not checking its return value. Not knowing that, it just spirals into undiagnosable misery from there. Yes, more of it on Win7. You must provide an STA thread, if this needs to run in the background then consider this solution.

WebClient and SOAP calls lock up in MonoTouch 4.0.0 and 4.0.1. Works in 3.2.6. Demo inside. What's causing it?

My app is making heavy use of webservice calls. Lately, some of the calls got stuck. After playing around I figured out that it
happens mostly for release builds
happens in the Simulator AND on the device (iPad, iOS 4.3)
happens more often on iPad 1 than on iPad 2
it is not limited to web services an SOAP but also affects the System.Net.WebClient
does not affest [NSString stringWithContentsOfUrl:] if invoked manually, since not bound
The effect is that the CPU load of the device drops to zero. memory is stable (in my demo project 8.5MB). If I put Console.WriteLines() everywhere, I can see that the code is stuck inside one of the WebClient.Download*() methods.
The code below demonstrates that (if built RELEASE with MT 4.0.1, LLVM off or on does not matter) downloading a file from the web over and over again fails sometimes right away on the first try, sometimes after 10 times, sometimes after around 30 downloads.
It is totally random. If you think it works, kill the app and restart it and eventually it will hang.
When building the same using MT 3.2.6, the downloading goes on all day without issues. It is impossible to break it.
MONO installed is the latest available version.
Can somebody from the MT team comment on it?
using System;
using System.IO;
using System.Threading;
using System.Net;
using System.Collections.Generic;
using System.Linq;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
namespace iOSTest
{
public class Application
{
static void Main (string[] args)
{
UIApplication.Main (args);
}
}
// The name AppDelegate is referenced in the MainWindow.xib file.
public partial class AppDelegate : UIApplicationDelegate
{
private Thread oThread;
// This method is invoked when the application has loaded its UI and its ready to run
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
// Make a release build and run on iPad 1 with iOS 4.3.2.
// Fails after downloading between 1 time and 30 times on MT 4.0.1.
// It is possible that it seems to work. Then just kill the app and restart and suddenly the effect
// will become visible. If you watch it with Instruments, CPU suddenly drops to zero. The app then is
// stuck somewhere inside WebClient. After about 10 minutes, an exception will be thrown (timeout).
// Never fails on MT 3.2.6
Console.WriteLine(MonoTouch.Constants.Version);
// A label that counts how often we downloaded.
UILabel oLbl = new UILabel(new System.Drawing.RectangleF(40, 100, 150, 30));
window.AddSubview(oLbl);
// This thread downloads the same file over and over again.
// The thread is not required to demonstrate the issue. The same problem occurs
// if the download is running on the main thread.
this.oThread = new Thread(delegate()
{
using(var oPool = new NSAutoreleasePool())
{
int i = 0;
while(true)
{
// Setup webclient and download a file from my website (around 2.4 MB)
WebClient oClient = new WebClient();
// It would be nice to hange it to your own URL to save me from all the traffic.
oClient.DownloadFile(new Uri("http://www.wildsau.net/image.axd?picture=2011%2f4%2fDSC05178.JPG"), Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "test.jpg"));
// Increase counter and update label.
i++;
this.InvokeOnMainThread(delegate { oLbl.Text = i.ToString(); });
Console.WriteLine("Done " + i + " times.");
}
}
});
// Have a button that starts the action.
UIButton oBtn = UIButton.FromType(UIButtonType.RoundedRect);
oBtn.SetTitle("Download", UIControlState.Normal);
oBtn.Frame = new System.Drawing.RectangleF(40, 40, 150, 30);
oBtn.TouchUpInside += delegate(object sender, System.EventArgs e)
{
this.oThread.Start();
};
window.AddSubview(oBtn);
window.MakeKeyAndVisible ();
return true;
}
// This method is required in iPhoneOS 3.0
public override void OnActivated (UIApplication application)
{
}
}
}
From Gonzalo-
When the problem occurs, "kicking" the threadpool by adding another
work item will make the problem go away.
Something like this (not tested or compiled ;-) should do:
Timer timer = new Timer (AddMe);
...
WebClient wc = new WebClient ();
Uri uri = new Uri(url);
timer.Change (0, 500); // Trigger it now and every 500ms
byte[] bytes = wc.DownloadData(uri);
timer.Change (Timeout.Infinite, Timeout.Infinite);
....
static void AddMe (object state)
{
// Empty.
}
#
Works 100% of the time - for me at least - YMMV. And it did, once we put the code under stress (Lots of files to download) it stalled again. Just heard from MT that 4.0.6 will have the fix in it. Should see it later this week!
Promised to be fixed by Xamarin in the next major release. Still does not work in 4.0.4 though.

Windows Phone 7 Audio Recording Problem

I'm hoping someone can help me with this. I have found the examples for recording audio using XNA in a Silverlight application. And it works, however, only the first time in. I have all the recording functionality on a seperate WP7 Page and with successive visits to the page it doesn't work. The best I can tell is the microphone.start is getting called but the micophone.status remains stopped. What is weird is the BufferReady keeps getting called and the code within that function is all running but without the microphone really starting nothing is really happening. When you exit the app and come back in again the first time visit to the page and everything works fine, but a revisit to the page and it doesn't.
void microphone_BufferReady(object sender, EventArgs e)
{
this.Dispatcher.BeginInvoke(() =>
{
microphone.GetData(buffer);
stream.Write(buffer, 0, buffer.Length);
TimeSpan tsTemp = timer.Elapsed;
TextBlockSeconds.Text = tsTemp.Hours.ToString().PadLeft(2, '0') + ":" + tsTemp.Minutes.ToString().PadLeft(2, '0') + ":" + tsTemp.Seconds.ToString().PadLeft(2, '0');
if(timer.Elapsed.Seconds >5)
DoStop();
});
}
private void ButtonRecord_Click(object sender, RoutedEventArgs e)
{
DisableRecordButton();
timer = new Stopwatch();
timer.Start();
stream = new MemoryStream();
TextBlockSeconds.Text = "00:00:00";
TextBlockStatus.Text = "Recording: ";
microphone.BufferDuration = TimeSpan.FromMilliseconds(500);
buffer = new byte[microphone.GetSampleSizeInBytes(microphone.BufferDuration)];
microphone.BufferReady += new EventHandler<EventArgs>(microphone_BufferReady);
microphone.Start();
}
private void DoStop()
{
if (timer.IsRunning)
timer.Stop();
if (microphone.State == MicrophoneState.Started)
{
microphone.Stop();
TextBlockStatus.Text = "Stopped: Ready to save";
}
else
{
TextBlockStatus.Text = "Ready: ";
}
TextBlockSeconds.Text = string.Empty;
EnableRecordButton();
}
Update...
I found the problem but no solution. I was calling the microphone.stop via code on a timer (so I could limit the recorded audio to 5 seconds). Exact same code to execute when a manual stop button would be clicked. When clicking the manual stop button everything worked fine, could re-visit the page and all would be fine. When the stop was called in code from the timer, next visit to the page would not work. So I implemented it with only a manual stop button but really would have been nice to do it automatically (and to know what the real issue was).
actually when you are navigating away from the page you can add
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
this.MicroPhone.BufferReady -= this.Microphone_BufferReady;
}
and when you are returning to page add
this.MicroPhone.BufferReady += this.Microphone_BufferReady;
You can add this statement either in a page loaded event or an OnNavigatedTo event
Added string name = System.Threading.Thread.CurrentThread.ManagedThreadId.ToString() to make sure that it was on the same thread (and it was).
But finally worked this out, the problem is the microphone.stop doesn't stop the microphone from continuing to fire the buffer ready event (like I was expecting). And it would seem the way the page is cached this causes some weird problems with that event still firing. So I added the code
microphone.BufferReady -= new EventHandler<EventArgs>(microphone_BufferReady);
to my code for stopping, and it all works now.
I can't see from your code how you're stopping the timer/microphone if you navigate away from the page and don't manually stop it.
If that's not it, are you ensuring that all your microphone operations are being executed on the same thread? (Just a thought.)

How do I tell my C# application to close a file it has open in a FileInfo object or possibly Bitmap object?

So I was writing a quick application to sort my wallpapers neatly into folders according to aspect ratio. Everything is going smoothly until I try to actually move the files (using FileInfo.MoveTo()). The application throws an exception:
System.IO.IOException
The process cannot access the file because it is being used by another process.
The only problem is, there is no other process running on my computer that has that particular file open. I thought perhaps that because of the way I was using the file, perhaps some internal system subroutine on a different thread or something has the file open when I try to move it. Sure enough, a few lines above that, I set a property that calls an event that opens the file for reading. I'm assuming at least some of that happens asynchronously. Is there anyway to make it run synchronously? I must change that property or rewrite much of the code.
Here are some relevant bits of code, please forgive the crappy Visual C# default names for things, this isn't really a release quality piece of software yet:
private void button1_Click(object sender, EventArgs e)
{
for (uint i = 0; i < filebox.Items.Count; i++)
{
if (!filebox.GetItemChecked((int)i)) continue;
//This calls the selectedIndexChanged event to change the 'selectedImg' variable
filebox.SelectedIndex = (int)i;
if (selectedImg == null) continue;
Size imgAspect = getImgAspect(selectedImg);
//This is gonna be hella hardcoded for now
//In the future this should be changed to be generic
//and use some kind of setting schema to determine
//the sort/filter results
FileInfo file = ((FileInfo)filebox.SelectedItem);
if (imgAspect.Width == 8 && imgAspect.Height == 5)
{
finalOut = outPath + "\\8x5\\" + file.Name;
}
else if (imgAspect.Width == 5 && imgAspect.Height == 4)
{
finalOut = outPath + "\\5x4\\" + file.Name;
}
else
{
finalOut = outPath + "\\Other\\" + file.Name;
}
//Me trying to tell C# to close the file
selectedImg.Dispose();
previewer.Image = null;
//This is where the exception is thrown
file.MoveTo(finalOut);
}
}
//The suspected event handler
private void filebox_SelectedIndexChanged(object sender, EventArgs e)
{
FileInfo selected;
if (filebox.SelectedIndex >= filebox.Items.Count || filebox.SelectedIndex < 0) return;
selected = (FileInfo)filebox.Items[filebox.SelectedIndex];
try
{
//The suspected line of code
selectedImg = new Bitmap((Stream)selected.OpenRead());
}
catch (Exception) { selectedImg = null; }
if (selectedImg != null)
previewer.Image = ResizeImage(selectedImg, previewer.Size);
else
previewer.Image = null;
}
I have a long-fix in mind (that's probably more efficient anyway) but it presents more problems still :/
Any help would be greatly appreciated.
Since you are using your selectedImg as a Class scoped variable it is keeping a lock on the File while the Bitmap is open. I would use an using statement and then Clone the Bitmap into the variable you are using this will release the lock that Bitmap is keeping on the file.
Something like this.
using ( Bitmap img = new Bitmap((Stream)selected.OpenRead()))
{
selectedImg = (Bitmap)img.Clone();
}
New answer:
I looked at the line where you do an OpenRead(). Clearly, this locks your file. It would be better to provide the file path instead of an stream, because you can't dispose your stream since bitmap would become erroneous.
Another thing I'm looking in your code which could be a bad practice is binding to FileInfo. Better create a data-transfer object/value object and bind to a collection of this type - some object which has the properties you need to show in your control -. That would help in order to avoid file locks.
In the other hand, you can do some trick: why don't you show streched to screen resolution images compressing them so image size would be extremly lower than actual ones and you provide a button called "Show in HQ"? That should solve the problem of preloading HD images. When the user clicks "Show in HQ" button, loads that image in memory, and when this is closed, it gets disposed.
It's ok for you?
If I'm not wrong, FileInfo doesn't block any file. You're not opening it but reading its metadata.
In the other hand, if you application shows images, you should move to memory visible ones and load them to your form from a memory stream.
That's reasonable because you can open a file stream, read its bytes and move them to a memory stream, leaving the lock against that file.
NOTE: This solution is fine for not so large images... Let me know if you're working with HD images.
using(selectedImg = new Bitmap((Stream)selected))
Will that do it?

Resources