New thread never completes waiting on WebBrowser - c#

In creating jpg images, this code uses threading. However, the Thread.Join() sometimes hangs on creating particular images. I have researched, and it seems as if I should be using BeginInvoke() instead. How could I rewrite the following code from using Thread.Join() to BeginInvoke()?
public Bitmap Generate()
{
var m_thread = new Thread(_Generate);
m_thread.SetApartmentState(ApartmentState.STA);
m_thread.Start();
m_thread.Join();
return m_Bitmap;
}
private void _Generate()
{
var browser = new WebBrowser {ScrollBarsEnabled = false };
browser.ScriptErrorsSuppressed = true;
browser.Navigate(m_Url);
browser.DocumentCompleted += WebBrowser_DocumentCompleted;
while (browser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
browser.Dispose();
}

Looking at your code I see one issue. You've registered to the DocumentCompleted event after the Navigate() call. So theoretically it's possible that the event have been fired before you've registered your handler.
Try to swap the two lines and see whether you get your problem fixed.
I believe that'll be the case if the image has already been retrieved and was cached.

Related

Cross-thread operation not valid: Control 'textbox' accessed from a thread other than the thread it was created on

I need some help. I started c# and not very familiar with event handling and threading yet. As a beginner and as time and exposure progresses, I would like to learn more on these advanced topics and improved and hope all of you here can help me.
I ran onto this problem of "Cross-thread operation not valid: Control 'textbox control called stackStatus' accessed from a thread other than the thread it was created on". I have tried to troubleshoot this whole day but simply no avail. I am stuck. :-( The program hits an exception and cannot continue to execute smoothly.
I have read the following threads and tried a few things but I guess I am still missing something. Appreciate if someone can help me out here. Thanks.
Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on
Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on
Here's are most of the portion of the code:
private void createCloud_Click(object sender, EventArgs e)
{
CreateCloud(); //start creation method
stackStatus.Text = "Creating stack..."; //updates the cloud status textbox
stackStatus.Refresh();
Cursor.Current = Cursors.WaitCursor; //change the cursor to wait state
Start_Describestack(); //call describe method to find out the status of cloud creation progress
Task.Delay(12000); // wait 12s in case not ready
Start_Describestack(); // call again describe method to find out the cloud creation progress status
Cursor.Current = Cursors.Default; //put cursor on wait
describeevents(); // call method to get all cloud creation event data and publish on the datagridview
}
private void Start_Describestack()
{
//method making use of timer to call
_timer = new System.Timers.Timer(15000);
_timer.Elapsed += new ElapsedEventHandler(describeStack);
_timer.Enabled = true;
}
delegate void describeStackCallBack(object sender, ElapsedEventArgs e);
private void describeStack(object sender, ElapsedEventArgs e)
{
//this method makes api calls through cloudclient to describe the stack
//this is where the "Cross-thread operation not valid: Control 'stackStatus' accessed from a thread other than the thread it was created on"
var client = new cloudclient();
var request2 = new StacksRequest();
request2.Cloudstackname = stackid;
try
{
var response = client.DescribeCloudStacks(request2);
foreach (var stack in response.Stacks)
{
//something is wrong here but I do not know how to fix it. Please help
if (this.stackStatus.InvokeRequired)
{
describeStackCallBack d = new describeStackCallBack(describeStack);
this.Invoke(d, new object[] { sender, e });
stackStatus.Refresh();
describevents();
}
else
{
stackStatus.Text = stack.StackStatus;
stackStatus.Refresh();
describeevents();
}
}
}
catch (Exception)
{
if (this.stackStatus.InvokeRequired)
{
describeStackCallBack d = new describeStackCallBack(describeStack);
this.Invoke(d, new object[] { sender, e });
stackStatus.Text = "Stack not found/Deleted";
}
else
{ stackStatus.Text = "Stack not found/Deleted"; }
}
describeevents();
}
private void describeevents()
{
var newclient = new cloudclient();
var request3 = new eventrequest();
request3.Cloudstackname = stackid;
try
{
var response = newclient.eventstack(request3);
dataGridView3.Rows.Clear();
foreach (var events in response.sevents)
{
dataGridView3.Rows.Add(events.Timestamp, events.ResourceStatus, events.ResourceType);
}
}
catch (Exception)
{
dataGridView3.Rows.Clear();
MessageBox.Show("Stack not ready!");
}
dataGridView3.Refresh();
}
Rather than doing :
stackStatus.Text = "some text";
Try :
stackStatus.Invoke((Action)delegate
{
stackStatus.Text = "some text";
});
Note that GUI element assignment outside the thread or they are declared is deprecated because the controls may no longer be available at any time.
There are two issues in your approach, which conspire to prevent your attempt to imitate the solution to the exception from working:
You have failed to note that the proposed solution calls itself, and in so doing, causes the foreach to be restarted for each time it's invoked from the worker thread.
You are following Microsoft canonical implementation of cross-thread-friendly Invoke()-based code, which IMHO is lame.
It is my opinion that there is no point in ever checking InvokeRequired. The standard pattern always involves situations where on the first entry, you know you will require Invoke(), and even if you didn't, there's no real harm in calling Invoke() when it's not necessary.
Instead, you should always keep separate the code that should run in the UI thread, and the code that does not. Then, in the code that does not, always use Invoke() to execute the code that does.
For example:
private void Start_Describestack()
{
//method making use of timer to call
_timer = new System.Timers.Timer(15000);
_timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
_timer.Enabled = true;
}
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
Invoke((MethodInvoker)describeStack);
}
private void describeStack()
{
var client = new cloudclient();
var request2 = new StacksRequest();
request2.Cloudstackname = stackid;
try
{
var response = client.DescribeCloudStacks(request2);
foreach (var stack in response.Stacks)
{
stackStatus.Text = stack.StackStatus;
stackStatus.Refresh();
describeevents();
}
}
catch (Exception)
{
stackStatus.Text = "Stack not found/Deleted";
}
describeevents();
}
That said, an improvement on the above would be to use System.Windows.Forms.Timer instead of System.Timers.Timer. The latter raises the Elapsed event on a worker thread, but the former raises its event on the UI thread, right where you want it. No Invoke() required at all.
You have at least one other problem with your code as well:
private void createCloud_Click(object sender, EventArgs e)
{
CreateCloud(); //start creation method
stackStatus.Text = "Creating stack..."; //updates the cloud status textbox
stackStatus.Refresh();
Cursor.Current = Cursors.WaitCursor; //change the cursor to wait state
Start_Describestack(); //call describe method to find out the status of cloud creation progress
Task.Delay(12000); // wait 12s in case not ready
Start_Describestack(); // call again describe method to find out the cloud creation progress status
Cursor.Current = Cursors.Default; //put cursor on wait
describeevents(); // call method to get all cloud creation event data and publish on the datagridview
}
In the above, the call to Task.Delay(12000); accomplishes nothing. The Task.Delay() method doesn't actually block the current thread. Instead, it returns an awaitable task object. The code in which it appears only is delayed if you wait on the returned object.
It's also questionable to call Start_Describestack() twice, because this method doesn't do anything except start the timer. Calling it twice means now you have two timers running.
Finally, you should also not have all those calls to Refresh() in your code. Correctly written Windows Forms code will not need anything like that. Updates to control properties will cause control invalidation automatically, and the control will update as needed at its next opportunity, which as long as the code is written correctly, will be soon enough for the user to not notice any significant delay.
Now, putting all of the above together, it seems to me that you should avoid using the timer altogether. There is still the potential problem that your call to DescribeCloudStacks() is a lengthy one, and could cause the UI to momentarily appear "stuck", which obviously isn't a desirable thing. In addition, the timer-based code, whether you require Invoke() or not, can be harder to understand, especially for someone new to asynchronous programming and threading.
Using the async/await feature, you can write the code in a conventional, procedural way, while still ensuring that the UI remains responsive, and that the UI-related code is always executed in the UI thread where it belongs. That might look something like this:
private async void createCloud_Click(object sender, EventArgs e)
{
CreateCloud(); //start creation method
stackStatus.Text = "Creating stack..."; //updates the cloud status textbox
Cursor.Current = Cursors.WaitCursor; //change the cursor to wait state
await describeStack(); //call describe method to find out the status of cloud creation progress
await Task.Delay(12000); // wait 12s in case not ready
await describeStack(); // call again describe method to find out the cloud creation progress status
Cursor.Current = Cursors.Default; //put cursor on wait
describeevents(); // call method to get all cloud creation event data and publish on the datagridview
}
private async Task describeStack()
{
var client = new cloudclient();
var request2 = new StacksRequest();
request2.Cloudstackname = stackid;
try
{
var response = await Task.Run(() => client.DescribeCloudStacks(request2));
foreach (var stack in response.Stacks)
{
stackStatus.Text = stack.StackStatus;
describeevents();
}
}
catch (Exception)
{
stackStatus.Text = "Stack not found/Deleted";
}
describeevents();
}
The above executes most of the describeStacks() method in the UI thread. The exception would be the DescribeCloudStacks() method call, which is run as a worker task. While it's running, the UI thread is free to operate normally. Execution of the describeStacks() method is temporarily put "on hold" (without blocking the UI thread) while the worker task runs, and then is resumed when it completes.
It's not clear from your original example whether you really wanted a repeating timer or not. The above doesn't use any loops; it calls the describeStack() method only twice, with a 12-second delay in between. But if you want a loop, you can do that as well. Just use the await Task.Delay() for the delay and await describeStack() for the operation, and put that in a loop as you like.
I don't see where the stackStatus object is created so I'm just guessing that you are creating it through a contructor for the class containing describeStack() and then you are registering an event handler for the click. I think what is happening is the event handler is being run on a different thread from the one in which the instance was created so you might have to change how you create the stackStatus object. That error is likely happening because whatever type the stackStatus was created from is known to not be reentrant so when the runtime detects access between threads it raises an exception so you are aware and can either prevent or recover from race-conditions or deadlocks.

How to keep thread alive until WebBrowser event fires

I have a thread with WebBrowser instance and I have attached to it an DocumentCompleted event. But from what I have observed, my event isn't raised, because thread ends before it happens. When I put MessageBox.Show on the end of thread, it gives time for the event to be raised. But how can I make thread wait for it without MessageBox?
WebBrowser browser;
Thread t = new Thread(() =>
{
string url = string.Format("webpage.com");
browser = new WebBrowser();
browser.ScriptErrorsSuppressed = true;
browser.Navigate(url);
browser.DocumentCompleted += browser_DocumentCompleted;
browser.DocumentCompleted += (o, a) =>
{
//MessageBox.Show("In DocumentCompleted.");
List<Status> statusy = new List<Status>();
IHTMLDocument2 currentDoc = (IHTMLDocument2)browser.Document.DomDocument;
//parsing the html doc
string Statuses = "";
foreach (Status status in statusy)
{
Statuses += String.Format("{0} {1} - {2} --> {3}{4}", status.Date, status.Time, status.Centre, status.Message, Environment.NewLine);
}
MessageBox.Show(Statuses);
};
MessageBox.Show("In thread!!!!");
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
You must call Application.Run(). Not just to ensure your thread doesn't end too soon, it is also required to get WebBrowser to raise its events. Using the message loop is a standard way in which heavily threaded components, like WebBrowser, ensure that its events are raised on the same thread that created the object. And it implements the STA contract.
The message loop that MessageBox.Show() uses under the hood to make itself modal is why it works right now when you use MessageBox. Not otherwise fundamentally different from the message loop that Application.Run() implements.
Use Application.ExitThread() to get the thread to end. It must be called on the same thread that called Application.Run(). That won't be a problem when you do it in the DocumentCompleted event handler.
The main problem is that the web browser control requires a proper message loop to work properly. The thread you're launching has no such message loop, so the web browser can't really do much.
The easiest solution would be to simply host the browser control in a form - this gives you easy control over the lifetime of the browser, and an easy way to maintain the message loop (that's what Application.Run does).
If that's not applicable for you (that is, you don't want to show any form at all), you'll need to make a form-less message loop. The simplest example using your code:
WebBrowser browser;
Thread t = new Thread(() =>
{
string url = string.Format("google.com");
browser = new WebBrowser();
browser.ScriptErrorsSuppressed = true;
browser.Navigate(url);
browser.DocumentCompleted += (o, a) =>
{
MessageBox.Show(browser.Document.Title);
Application.ExitThread();
};
Application.Run();
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
If you need to wait on the event from some other thread, there's plenty of ways to synchronize. A simple way to pass data at the same time and with a nice Task-based interface is the TaskCompletionSource class. For example, if I want to await the title of the document asynchronously, it's as simple as this:
WebBrowser browser;
var tcs = new TaskCompletionSource<string>();
Thread t = new Thread(() =>
{
string url = string.Format("google.com");
browser = new WebBrowser();
browser.ScriptErrorsSuppressed = true;
browser.Navigate(url);
browser.DocumentCompleted += (o, a) =>
{
tcs.SetResult(browser.Document.Title);
Application.ExitThread();
};
Application.Run();
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
Console.WriteLine(await tcs.Task);
Of course, this assumes the callee is an async method, but there's plenty of other things you can do with the task - for example, register a continuation.
You don't need to keep a reference to the Thread instance - started threads are roots, so they will never be collected.
How about setting a flag in the DocumentCompleted event handler, and then waiting for the flag to be set where you are currently doing the MessageBox.Show()?
Use a flag. In the DocumentCompleted event handler, set the flag to false.
Then use a while statement like:
bool Flag = true;
browser.DocumentCompleted += (o, a) =>
{
//MessageBox.Show("In DocumentCompleted.");
List<Status> statusy = new List<Status>();
IHTMLDocument2 currentDoc = (IHTMLDocument2)browser.Document.DomDocument;
//parsing the html doc
string Statuses = "";
foreach (Status status in statusy)
{
Statuses += String.Format("{0} {1} - {2} --> {3}{4}", status.Date, status.Time, status.Centre, status.Message, Environment.NewLine);
}
MessageBox.Show(Statuses);
Flag = false;
};
while (Flag) { }

Implicit function evaluation: webbrowser in thread, body always null [duplicate]

Problem Scope:
I'm writing an aplication to save the HTML's retrieved from the Bing and Google searches. I know there are classes to execute the Web Requests using stream such as this example, but since Google and Bing both use Javascript and Ajax to render the results into the HTML, there's no way i can simply read the stream and use get to the result i need.
The solution to this, is to use the WebBrowser class and navigate to the url i want, so that the Browser itself will handle all the Javascript and Ajax scripting executions.
MultiThreading:
In order to make it more efficient, i have the same Form aplication firing a thread for each service (one for Bing, and one for Google).
Problem:
Since i need the WebBrowser, i have instantiated one for each thread (which are 2, at this moment). According to Microsoft, there is a known bug that prevents the DocumentCompleted event from firing if the WebBrowser is not visible and is not added to a visible form aswell (for more information, follow this link).
Real Problem:
The main issue is that, the DocumentCompleted event of the browser, never fires. Never.
I have wrote a proper handler for the DocumentCompleted event that never gets the callback. For handling the wait needed for the Browser event to fire, i have implemented a AutoResetEvent with a high timeout (5 minutes), that will dispose the webbrowser thread if it does not fire the event i need after 5 minutes.
At the moment, i have the Browser created and added into a WindowsForm, both are visible, and the event is still not firing.
Some Code:
// Creating Browser Instance
browser = new WebBrowser ();
// Setting up Custom Handler to "Document Completed" Event
browser.DocumentCompleted += DocumentCompletedEvent;
// Setting Up Random Form
genericForm = new Form();
genericForm.Width = 200;
genericForm.Height = 200;
genericForm.Controls.Add (browser);
browser.Visible = true;
As for the Navigation i have the Following (method for the browser) :
public void NavigateTo (string url)
{
CompletedNavigation = false;
if (browser.ReadyState == WebBrowserReadyState.Loading) return;
genericForm.Show (); // Shows the form so that it is visible at the time the browser navigates
browser.Navigate (url);
}
And, for the call of the Navigation i have this :
// Loading URL
browser.NavigateTo(URL);
// Waiting for Our Event To Fire
if (_event.WaitOne (_timeout))
{
// Success
}
{ // Error / Timeout From the AutoResetEvent }
TL:DR:
My WebBrowser is instantiated into a another STAThread, added to a form, both are visible and shown when the Browser Navigation fires, but the DocumentCompleted event from the Browser is never fired, so the AutoResetEvent always times out and i have no response from the browser.
Thanks in Advance and sorry for the long post
Although this seems a strange way, here is my attempt.
var tasks = new Task<string>[]
{
new MyDownloader().Download("http://www.stackoverflow.com"),
new MyDownloader().Download("http://www.google.com")
};
Task.WaitAll(tasks);
Console.WriteLine(tasks[0].Result);
Console.WriteLine(tasks[1].Result);
public class MyDownloader
{
WebBrowser _wb;
TaskCompletionSource<string> _tcs;
ApplicationContext _ctx;
public Task<string> Download(string url)
{
_tcs = new TaskCompletionSource<string>();
var t = new Thread(()=>
{
_wb = new WebBrowser();
_wb.ScriptErrorsSuppressed = true;
_wb.DocumentCompleted += _wb_DocumentCompleted;
_wb.Navigate(url);
_ctx = new ApplicationContext();
Application.Run(_ctx);
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
return _tcs.Task;
}
void _wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
//_tcs.TrySetResult(_wb.DocumentText);
_tcs.TrySetResult(_wb.DocumentTitle);
_ctx.ExitThread();
}
}

Form design messed up when using Show()

I'm trying to make a loading screen window. I use Show() instead of ShowDialog() because I have some code to execute after showing it. When using ShowDialog() form is fine but when using Show() form is messed up. What is causing this and what is the solution? Here is how I did it:
bool closeLoadingWindow = false;
void ShowLoadingWindow()
{
LoadingWindow loadingWindow = new LoadingWindow();
loadingWindow.Show();
while (!closeLoadingWindow);
loadingWindow.Close();
return;
}
public MainWindow()
{
Thread loadingWindowThread = new Thread(ShowLoadingWindow);
loadingWindowThread.Start();
InitializeComponent();
// ...
closeLoadingWindow = true;
}
When using ShowDialog():
When using Show():
The reason ShowDialog is working is because your while loop won't be executing, once the runtime hits that line of code it will stop processing until the form is dimissed.
Your code doesn't make sense, the point of using a thread here is to keep the "busy" code (your while loop) out of the main UI thread so it doesn't block. However, you are trying to create/show your form on the same thread, and a non-UI thread at that.
You don't necessarily need to use Show here, you can use ShowDialog but it is a little bit trickier in terms of dimissing the form etc. However, to solve the problem you have at the minute I would recommend you do:
LoadingWindow _loadingWindow;
void ShowLoadingWindow()
{
if (_loadingWindow == null)
_loadingWindow = new LoadingWindow();
_loadingWindow.Show();
}
void HideLoadingWindow()
{
if (_loadingWindow != null)
{
_loadingWindow.Close();
_loadingWindow.Dispose();
}
}
void LoadSomething()
{
while (...)
{
// busy code goes here
}
// after code is finished, close the form
MethodInvoker closeForm = delegate { HideLoadingWindow(); };
_loadingWindow.Invoke(closeForm);
}
public MainWindow()
{
ShowLoadingWindow();
new Thread(LoadSomething).Start();
}
}
FYI - Depending on the nature of exactly what your trying to do in the thread it might be a better approach to use the Task Parallel Library rather than creating a dedicated thread, various benefits like continuation / cancellation support.

TwainDotNet Scanning using TWAIN with BackgroundWorker

Has anyone tried TwainDotNet for scanning with TWAIN API calls from .NET? Though it works well usually I've some issues with it when used along with WPF application using MVVM. Basically I'm calling Twain scanning functions from a Service, which in turn uses a BackgroundWorker.
List<BitmapSource> bitmapSources = new List<BitmapSource>();
Twain twain = new Twain(new WpfWindowMessageHook(_window));
ScanSettings settings = new ScanSettings() { ShowTwainUI = false };
using (BackgroundWorker worker = new BackgroundWorker())
{
worker.DoWork += (sndr, evnt) =>
{
AutoResetEvent waitHandle = new AutoResetEvent(false);
EventHandler scanCompleteHandler = (se, ev) => { waitHandle.Set(); };
twain.ScanningComplete += scanCompleteHandler;
twain.StartScanning(settings);
waitHandle.WaitOne();
if (twain.Images.Count > 0)
{
foreach (var image in twain.Images)
{
BitmapSource bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(new Bitmap(image).GetHbitmap(),
IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
bitmapSources.Add(bitmapSource);
}
}
};
worker.RunWorkerCompleted += (sndr, evnt) => { image1.Source = bitmapSources[0]; };
worker.RunWorkerAsync();
}
ScanningComplete event handler is never fired when we are working with a BackgroundWorker. Any suggestions to resolve this issue?
The fact that the Twain object requires a window handle in its object constructor suggests that something inside the Twain object requires message handling. Cross-thread message handling is tricky to begin with but even more so when it's happening inside an API.
If the twain API creates a window handle (overtly, such as a popup window or dialog, or secretly, such as for interprocess communication (IPC)) as part of one of the API functions you're calling from the background thread, that window handle will be bound to the thread it was created on - the background thread. All messages sent to that window handle will queue up waiting for the background thread to process them in a message loop. You don't have a message loop in your background thread, so that window handle will get stuck in limbo. It won't respond to window messages. Posted messages will go unanswered. SendMessage() will deadlock.
Even if this is not a window handle / message loop problem, it is very likely that if the Twain API was not explicitly and deliberately implemented with multithreading in mind, it will have problems when used across threads. You are creating the twain object in one thread and then using it in another thread, so this is a cross-thread situation. If you could create the twain object in the background thread and only use the twain object in the context of that background thread, this might work around thread affinity issues in the twain API implementation. When window handles and messages are involved, moving everything to the background thread is just as likely to make things worse.
The ability to use an object across threads does not come for free. If the twain API was not designed for use across threads, there is little you can do to make it work across threads. Your best bet is to keep the Twain object in the main UI thread.
Have you tried removing the LINQ'ness from the code and put it into a separate function to actually test this out first, note that I have it wrapped up in a try/catch block to see if there's any error, also notice that I created a simple class WorkerArgs for passing the data around as it is non-LINQ code, it would be interesting to see what results there are (if any):
public class WorkerArgs{
public List<BitMapSource> _bitmapSources;
public Twain _twain;
public ScanSettings _settings;
}
List<BitmapSource> bitmapSources = new List<BitmapSource>();
Twain twain = new Twain(new WpfWindowMessageHook(_window));
ScanSettings settings = new ScanSettings() { ShowTwainUI = false };
WorkerArgs wArgs = new WorkerArgs();
wArgs._bitmapSources = bitmapSources;
wArgs._twain = twain;
wArgs._settings = settings;
using (BackgroundWorker worker = new BackgroundWorker())
{
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.RunWorkerAsync((WorkerArgs)wArgs);
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
try{
image1.Source = (WorkerArgs(e.Argument))._bitmapSources[0];
}catch(Exception up){
throw up; // :P
}
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
try{
WorkerArgs thisArgs = (WorkerArgs)e.Argument as WorkerArgs;
if (thisArgs != null){
AutoResetEvent waitHandle = new AutoResetEvent(false);
EventHandler scanCompleteHandler = (se, ev) => { waitHandle.Set(); };
thisArgs._twain.ScanningComplete += scanCompleteHandler;
thisArgs._twain.StartScanning(settings);
waitHandle.WaitOne();
if (thisArgs._twain.Images.Count > 0)
{
foreach (var image in twain.Images)
{
BitmapSource bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(new Bitmap(image).GetHbitmap(),
IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
thisArgs._bitmapSources.Add(bitmapSource);
}
}
}
}catch(Exception up){
throw up; // :P
}
}
I couldn't help noticing, it's just after entering the code I noticed this:
Twain twain = new Twain(new WpfWindowMessageHook(_window))
Are you doing hooking or something like that within the background worker - perhaps there's a cross thread problem hence ScanningComplete is not being fired? Just a thought, Can you clarify anyway?

Categories

Resources