象外行一样思考,象专家一样实践。
coolbean | 10 九月, 2007 02:02
Download code:
coolbean | 10 九月, 2007 01:42
Run code asynchronously with this simple and elegant design model
Ever since VB5 service pack 2, there has been the possibility of running VB applications multi-threaded by using ActiveX EXEs. However, if you try and research this you will find it is fiddly to get working. This article presents a method which makes running operations asynchronously really easy.
Although ActiveX EXEs can run in a new thread, I've never really understood how to get it working: you need to use CreateObject to make the object on a new thread, and then you need to be very careful as to how you start the work you want to do asynchronously. Most times you find that VB blocks until the method call is complete regardless of whether the object is in a new thread or not.
What you want to be able to do is to say I want to perform some operation asynchronously and I would like to be notified when it is complete. This project demonstrates a tiny code module and a type library you can add into your own ActiveX projects to do just that. It is based around a part of the MSDN "CodeFlow sample" (see downloads).
The main problem with getting a multi-threaded application up and running is how to call a method in VB without the caller being blocked. It turns out there is a simple solution to this problem. The steps are as follows:
This solves the problem because the method you call immediately yields control back to the caller, and then it is left to Windows pre-emptive multi-tasking to raise the timer event and kick off the process within the ActiveX EXE. There is no further interference because the ActiveX EXE is running in a different process to the caller.
To stop having to have a form in the ActiveX EXE, this solution is based on a Win32 API timer. Win32 API timers come in two flavours: either they notify the application when they tick by posting a WM_TIMER message to a window, or they fire a callback interface. This solution uses the callback interface, and as a consequence must be implemented within a module (because VB will not provide the address of a function to callback to for any function within an object, only one in a module).
Because the code to start the object is implemented in a module, the module must have a reference to the object instance it has to start when the timer fires. To achieve this without the possibility for errors, an interface is defined that the object can implement and the module will only use this for communication. In this sample, the interface is defined in a Type Library called Runnable. This allows you to reference the Type Library without having to declare it as a public class from the ActiveX executable.
The final implementation feature is the use of the OLE/COM API call CoLockObjectExternal to ensure that the object being started asynchronously isn't inadvertently terminated by the caller before the timer has had a chance to be fired.
Here is the code in the mStart.bas module:
coolbean | 05 九月, 2007 23:51
EnableWindow hwnd,0
Note: EnableWindow function sends WM_CANCELMODE to the combobox control.
coolbean | 02 九月, 2007 15:02
coolbean | 02 九月, 2007 15:00
| « | 九月 2007 | » | ||||
|---|---|---|---|---|---|---|
| 一 | 二 | 三 | 四 | 五 | 六 | 日 |
| 1 | 2 | |||||
| 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| 10 | 11 | 12 | 13 | 14 | 15 | 16 |
| 17 | 18 | 19 | 20 | 21 | 22 | 23 |
| 24 | 25 | 26 | 27 | 28 | 29 | 30 |