Selasa, Desember 12, 2006

Visual Basic – ActiveX EXE Tutorial

Just what the heck is an ActiveX EXE? How do I use it and more importantly, why?

An ActiveX EXE is a special type of COM component that is used in specific circumstances. Yes, it is an EXE file, meaning it is loaded into its own address space and given its own process and threads, but it is designed to be an OLE automation server, just like an ActiveX DLL. In other words, it has no forms, has no “starting” point like a sub Main() and exposes interfaces (classes) to be used by a client application, just like an ActiveX DLL.

OK, if an ActiveX EXE is so similar, why would I choose to use an ActiveX EXE over an ActiveX DLL you may ask? Good question but let me explain how an ActiveX DLL works first, before I tell you about an ActiveX EXE.

An ActiveX DLL is mapped into the address space of the client application and becomes part of client’s process; the ActiveX DLL does not spawn its own thread. This means, in versions prior to VB.Net any way, the thread of the client application must yield processing and give that thread to the ActiveX DLL to use. This gives you synchronous processing; the calling application can not continue until the ActiveX DLL returns from the method call. This is a form of Apartment Threading; the DLL is not single threaded, that would mean all of the classes given out to clients would share the same thread, in Apartment Threading, each class is dependant on the thread given to it by the client application and all of those threads work independently.

An ActiveX EXE on the other hand creates a new thread for each new class that it creates! Each thread is independent of the client application. Hold on their Guru, are you talking about Multi-threading in a VB application??? Your damn straight, you can create a fully multi-threaded application by just creating classes from an ActiveX EXE. So, you can create an asynchronous call, meaning that the client application can continue processing while the ActiveX EXE is processing too. Just be sure to notify the client application that processing has either finished or has an error. The best way to do this is to create an event in the ActiveX EXE, then when creating the ActiveX EXE class, declare it with the “With Events” keyword.

Ok, sounds great, but when am I ever going to use it? As Scotty on Star Trek would say, “The right tool for the right job”, an ActiveX EXE is a tool and there is specific reasons when and why you would use it. The number one reason not to use it is when you will be transferring large amounts of data between the client and COM component. Remember, and ActiveX EXE is running out side of the clients processes, meaning, they can not pass data directly between the two, the operating system must “Marshall” the data back and forth, this creates a tremendous amount of over head and can significantly slow down the processing time; not a good idea.

There is also a “Gotcha” involved in an ActiveX EXE, they do not always work as stated, yes, the class does have its own thread and yes that thread is independent from the client application, but in VB anyway, the VB main thread does have a tendency to yield, just like a DLL. The work around that I have used in the past is to include the “timer Lite” DLL that you will find in our code section. I have the client call the main method, that method starts a timer for less then one second and returns to the client application. When the timer fires, I then call an internal (private) method that will execute the code the client thought was going to process. I know this sounds confusing, but it will all come together when we do the sample.

So, if passing data back and forth is very light and you need to process something independently of the client application, or you what something to run strictly firing it’s own events with minimal interaction with the client application, an ActiveX EXE could be your savior.

Let me give you an example of when I have used an ActiveX EXE in the past.

I needed to create an IVR (Interactive Voice Response, you know, press 1 for this, press 2 for that) system. It was to have 96 lines coming in and each line must run independently, it must have a “Master Control” application that controls the whole thing, for example, start and stop the system and monitor what is going on in the system, detect “dead” lines, clear them and re-start that line again.

OK, I need 96 instances of something that work independently of each other and independently of the client application. The thing I need to create will have minimal communications with the client except for sending up a few messages to let it know what is going on. Hmmmmm…..Sounds like a job for an ActiveX EXE to me, what do you think?

The final product worked like this. A VB based application would start, it would check the IVR board to see how many lines are available. It would then create that many instances of a class in an ActiveX EXE (in this case, 96), it would then pass a line to the class to monitor; the VB app then just sat back and waited.

The EXE class would handle it’s own events, for example “Line Ring”, and would process the call, it would send up a message to the VB app via an event to let the VB app know the line was being used and when it was finished with a call.

Sounds kind of nifty eh? And it worked like a charm.

OK, let’s build an demo client and ActiveX EXE.
Note: You will need to download the Timer Lite project and register it before we begin.
Start the VB IDE and select ActiveX EXE from the project templates. You should now have a project called Project1 and one class called Class1. Right click the project and select Project Properties, change the project name to MyFirstEXE and check off the “Unattended Execution” option. Most COM objects and ALL DCOM objects should run as Unattended Execution, this prevents a pop up box from displaying on the users screen, it will write any errors to the event log instead. Change the threading model to “Thread Per Object”, this will give you the multi-threading. Now press OK.

Next, rename Class1 to clsMain.

Add a reference to the TimerLite.DLL.

We now need to add an event to our Class so we can notify our client application when processing has been completed. We also need to add a timer and a var to hold the value passed to the main sub to our class, Paste in the following code in the top you clsMain:

Option Explicit


'* Class Name: clsMain *

'* Date: Tuesday, January 29, 2002 *

'* Author: The VB Guru *

'* Compiler: Microsoft Visual Basic 6.00 sp4 *

'* Synop: This is a demo to show how to create and use an ActiveX EXE *

'* *


Private WithEvents ProcTimer As TimerLite.clsTimerLite

Public Event Finished(Message As String)

Private lLoops As Long

We now need to add the code for the client application to call, paste in the following code:

Public Sub MakeMeProcess(ByVal NumberOfLoops As Long)


'* Sub Name: MakeMeProcess *

'* Date: Tuesday, January 29, 2002 *

'* Author: Kevin Henderson *

'* Compiler: Microsoft Visual Basic 6.00 *

'* Args: *

'* Long: NumberOfLoops -- This is the number of seconds you want *

'* The EXE to process on it's own. *

'* Synop: For demonstration purposes, we are going to simulate this EXE *

'* Running on it's own, this will be done by way of a timer. *

'* We also have to prevent the VB thread from yielding, I *

'* Said in the tutorial, we need to create a timer here too so the *

'* Sub will return right away and the timer will call the function *

'* we want. *

'* *


Set ProcTimer = CreateObject("TimerLite.clsTimerLite")

With ProcTimer

.Interval = 500

.Enabled = True

End With

lLoops = NumberOfLoops

End Sub

As you can see, we are setting the timer and setting the class level var to hold the value the client is passing.

Lets now add the code for when the timer fires, this code will call our hidden internal code to do the job the client wants.

Private Sub ProcTimer_Timer()

With ProcTimer

.Interval = 0

.Enabled = False

End With

IntMakeMeProcess lLoops ' When the timer fires, call the internal function that the user thought they were calling

Set ProcTimer = Nothing

End Sub

Now the Internal sub,

Private Sub IntMakeMeProcess(ByVal NumberOfLoops As Long)


'* Sub Name: IntMakeMeProcess *

'* Date: Tuesday, January 29, 2002 *

'* Author: The VB Guru *

'* Compiler: Microsoft Visual Basic 6.00 *

'* Args: *

'* Long: NumberOfLoops -- This is the number of seconds you want *

'* The EXE to process on it's own. *

'* Synop: As you can see, this sub is Private and can only be called from *

'* within this class. It is only called when the ProcTimer fires *

'* And passes the same value as MakeMeProcess(). This allows the *

'* VB thread to continue processing and the thread in this class to *

'* Process at the same time. *

'* *


Dim counter As Long

' do some processing, in this case we are just going to loop to simulate some lengthy process.

For counter = 0 To NumberOfLoops



RaiseEvent Finished("All done") ' Let the client know we are done

End Sub

And of course, a bit of clean up code

Private Sub Class_Terminate()

Set ProcTimer = Nothing ' Clean up time

End Sub

That is it, just compile your EXE, then right click the project to bring up the properties, click on the Component tab and select “Binary Compatibility” to make sure every time you compile it will still work with your client applications. Click the run button and we are all set to create our client.

Open a new instance of VB, no, you can not do it like an ActiveX DLL and create a project group, remember, an EXE runs in its own process and you must debug it the same way, in its own VB instance.

Select Standard EXE as the Project template, you should now have a project called Project1 and one form called Form1, these are fine, you do not need to change the names. Add a reference to “MyFirstExe” in the Project -> References menu, you also need to add a button to your form.

We now need to declare an instance of our ActiveX EXE class, remember, this class has events that we want to fire so we must declare it as such. Paste the following code into the declaration section (the top) of your form.

Option Explicit

Private WithEvents MyEXE As MyFirstEXE.clsMain

Now we need to initialize the object, paste this code in the form load event:

Set MyEXE = New MyFirstEXE.clsMain

Now add this code to the MyEXE_Finished event:

MsgBox Message

We now need code to make it all come together, paste this code into your Command_click event:

MyEXE.MakeMeProcess (1000) ' Make the ActiveX simulate processing by doing 1000 loops

Some clean up code and we are all set:

Private Sub Form_Unload(Cancel As Integer)

Set MyEXE = Nothing

End Sub

Now, run the standard EXE, press the command button and within a second or two, you should have a message box pop up telling you the EXE has finished.

To prove that the EXE is running on it’s own thread, set the number you pass to the EXE well past the 1000 number I have set as the default, say 10 or 20K. While you are waiting for the message box, click on the title bar of your standard EXE and move the window around. If this was an ActiveX DLL, you would not be allowed to do this.

You can set break points in your ActiveX EXE and step from your Standard EXE right into the ActiveX EXE, just like it was in a project group.

I hope this helps you out and you at least have a basic understanding on what an ActiveX EXE is and how it differentiates from an ActiveX DLL.

You can download the complete project Here, but you will still need to download the TimerLite DLL from the Code Section. If you download the code, do not forget to compile or double click on the ActiveX EXE to register it before you try to run the Standard EXE, or else the Standard EXE will not be able to find the Active X EXE.

Copy write 2002 by K & K Consulting and the VB Guru

1 komentar:

Anonim mengatakan...

salam kenal, mas. saya mau nanya, cara mengaktifkan activex control di vb itu gimana ??
terima kasih, mas.