C# Best approach for a responsive UI during SQL query using COM interop
I am making a C# DLL plugin for a EXE written in V开发者_Go百科B6. I do not have access to the source of the EXE. The DLL itself works and communicates fine with the EXE.
Here is the process for a event:
- User issues command on EXE which then calls a function in the DLL, passing an object as a parameter
- DLL processes data which sometimes takes a long time
The DLL responds by calling a function of the object that was passed. The DLL function itself does not return anything
public void DoCommand(object CommandSettings) { //ObjectVB6 is my custom class to allow easy calling of COM methods and properties ObjectVB6 CS = new ObjectVB6(CommandSettings); ... //process data CS.CallMethod("MyReply", args); }
My problem is that during long queries (from the DLL), the EXE's UI freezes.
What is the best way to prevent this? I have tried using asynchronous MySQL queries, which were no good, and tried using multiple threads, which just run into protected memory issues.
Any advice you can provide would be awesome. Been trying to address this issue for days. Thanks.
Try the following:
BackgroundWorker bw = null;
ObjectVB6 CS = null;
public void DoCommand(object CommandSettings)
{
//ObjectVB6 is my custom class to allow easy calling of COM methods and properties
CS = new ObjectVB6(CommandSettings);
// hook up background worker
bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}
private void bw_DoWork(...)
{
// process data, e.g. the piece that takes too long
}
private void bw_RunWorkerCompleted
{
CS.CallMethod("MyReply", args);
}
Like one of the responders said, this may or may not work due to the nature of VB6 apartment threading.
Why can't you just use a worker thread for that code? What "protected memory issues" are you running into?
IMO the best way to deal with this is to throw your request into the ThreadPool
on the DLL side, "fire and forget" style. Have you tried this?
Otherwise you'll have to jigger up a callback function to your VB6 program to get status, which, as you may have already found out, is tricky due to VB6's Single-Threaded Apartment model.
If you want to explore the perils and rewards of multi-threading in VB6 in greater depth, have a look at the following article. It may allow you do simply start up a thread and do it on the VB6 side:
Multi-Threading In VB5 and VB6
http://www.freevbcode.com/ShowCode.Asp?ID=1287
All functions developed in .NET can be called asynchronously using a delegate and then calling BeginInvoke to actually call the function. Since your function does not return anything, you won't need to call EndInvoke. By making use of IAsyncResult you can meet your Callback requirement. A good reference for how to do this properly is "Programming .NET Components" by Juval Lowy published by O'Reilly. The ISBN is 0596102070. Good Luck.
I've figured a way to accomplish what I was after. While I would prefer a nicer method, this way works.
Used two queues to share information. Main thread listens to get _get queue, and sets the _set queue when a request is made. Worker thread simple inserts request into _get queue, and waits until _set is ready. The main thread is just acting like a proxy.
Thanks for your help!
精彩评论