Turning the sieve of Eratosthenes into an ActiveX control is a really bad idea. The only reason I did it was to show how bad an idea it is. You pay a performance penalty. You get no particular convenience benefit. Don’t pay more for less.
I’ve already complained about controls that shouldn’t be controls (Timer and CommonDialog). Don’t add yours to the list. In fact, I advise you to skip the rest of this section and go back to the “Performance” sidebar on page 551 to see for yourself how much slower a control is than an ActiveX DLL with exactly the same code.
I had to use a slightly different technique to create the ActiveX control versions of the sieve server. You start by creating a new ActiveX control project, but you can’t just rename the CSieve class as a UserControl. Instead, you copy the text out of the CLS file and copy it into a new CTL file. That’s really all you need to create a working control, but of course, there’s a little more to it if you want your control to at least pretend it’s a real control.
First, your control should have a visual representation at design time so that you can find it and delete it after you’re done proving that a nonvisual control is a bad idea. I created a simple sieve bitmap for the Toolbox and put the same bitmap on the control surface. I also added a label with the word Sieve in a nice bold font. But there’s no reason to show this junk on the client’s surface at run time, so you turn it off by setting the InvisibleAtRuntime property of the UserControl to True.
In controls, you should do initialization tasks both in the UserControl_ReadProperties and UserControl_InitProperties events by raising the UserControl-_Load “event” described in Chapter 9, page 483. These are the same kinds of tasks that you would do in Class_Initialize or Form_Load for classes or forms, respectively. The ReInitialize method is called by Class_Initialize in the CSieve class, but UserControl_Initialize happens too early in the XSieve controls. ReInitialize needs to use the MaxPrime property, but properties aren’t initialized until after UserControl_ReadProperties reads them from the PropertyBag. Initialization should be done at this point. UserControl_ReadProperties doesn’t happen when the control is created, so the same initialization code needs to be called in UserControl_InitProperties.
The sieve server has several properties, but only one of them—MaxPrime—is appropriate for setting at design time in the Properties window. The Sieve
Client program doesn’t use it even then. Instead, it gets the appropriate value from the user at run time. Other properties, such as NextPrime and Primes, are read-only properties that can be calculated only at run time, so they’re disabled in the Properties window.
None of these minor differences adds any advantage for the client. Most controls with no user interface are nothing more than an annoyance.