Dynamic web pages with ActiveX and VBScript
UNDER CONSTRUCTION
Introduction
ActiveX is a lighter version of COM components since they are meant to be
included in web pages to be dowloaded and run on the user's computer. Once this
component has been downloaded, it will run locally every time the user accesses
a page which makes use of this component.
Arguments against using...
- ... client-side binaries: They are too big a risk. This is definitely
a risk, but you can lower security only for your site by adding the domain
in the Trusted Sites section
- ... ActiveX components as opposed to Java applets: Compared to Java
applets, ActiveX present more security risk right from the start since it
is allowed to perform any operation that the logged on user can do. Java
applets, on the other hand, run in the so-called "sandbox" mode
by default, and only signed applets, if accepted by the user, have full
access to the computer.
But then, by using Trusted Sites, they don't
take more risk than running a dedicated application gone berserk... If they
trust you with dedicated applications (they do trust you, right?),
then downloading the same kind of code from your site as an ActiveX component
makes no difference.
Besides, starting with XP, Microsoft no longer
ships a JVM: Not having to install this yourself on all the client hosts
and set their Internet Explorer to run Java applets is a big plus.
- ...VBScript over JavaScript: VBS is only supported by Internet Explorer,
but considering its market share...
- ... ActiveX and VBScript as opposed to non-proprietary solutions: Fact
is, using ActiveX and VBS locks you (to develop your web application as
an ActiveX component) and your customers (since as of Nov 2003, only IE can work with ActiveX
and VBS, although people are working to allow Mozilla
to support ActiveX) into using Microsoft products.
On the other hand, and unlike
the .Net architecture (at least unless the DotGNU and Mono projects fail),
you are free to use any OS and web server to host your ActiveX/VBS-filled
web pages.
And, again, considering Windows' market share, is it really
a sound decision to dump this solution just to satisfy the 10% of users
not using Windows as their OS and/or Internet Explorer as their browser,
especially when the alternatives, whether they are Java applets or server-side
scripting, are such a pain?
Another good point about moving the logic into downloadable components
to run on the client host is that your application can be accessed offline by
just downloading your site with an offline-browser, and accessing the off-line
archive via eg. C:\site\index.htm as the URL. Great if your customers
experience occasional problems connecting to the Net.
Stuff that is missing in OCX as used in IE:
- No menus (merged with IE's)
- Show() method doesn't exist (always shown when called)
- non-modal forms N.A.
- You cannot use End, as a control is unloaded only once its container
is closed
Finally, since the application run on the client host, data can also be located
on the customer's hosts instead of your web server. Few companies feel confortable
having their business data over in some database server on the Net...If your
needs are small, I recommend that you take a look at SQLite,
a high-performance, open-source SQL engine based on a single 200KB DLL, which
can be distributed through a CAB as part of the fixed cost stuff that must be
installed on all client hosts prior to using your web application.
By default, VB does not ensure binary compatibility, which is a must if you
don't want to update a control's CLSID in its web page every time you recompile.
You must, however, update its version number in the web page (and the INF if
you package a control in a CAB.)
FYI, I took a quick look at ActiveX Documents (EXEs, but DLLs work the same,
expect they run in IE's space), and witnessed frequent IE crashes.
Important: If copy/pasting samples from a web page, in case a control
doesn't load, make sure you replace all spaces, which may be turned into invisible
characters that prevent correct parsing of the web page by IE (been there...)
Developing an ActiveX control
Since the compile-update INF-update HTML-restart IE is too much work when
you're still working on the code... make use of VB's capability to host more
than one project in the IDE (File | Add new project), so you can have a regular
EXE project with a single form, which will contain the ActiveX control you are
working on. The IDE will recompile (reinterpret ;-)) the OCX every time you
hit F5 to run its contained, ie. the EXE, since an ActiveX control just needs
a container, and doesn't care whether it's the VB IDE or Internet Exploder.
Notes:
- UserControl_Initialize() is called every time the control is loaded,
which explains why this event is triggered when you hit F5 to launch its
container AND when you stop the project, and go back to design mode when
the control is reloaded in the form
- Set the control's background color through AMBIENT:
Private Sub
UserControl_InitProperties()
UserControl.BackColor
= UserControl.Ambient.BackColor
End Sub
- If a control doesn't show in the form, make sure its size is big enough
in the form, or it is clipped when the form is running
- If the control looks smaller when shown in IE than it is when shown
running in a form in the IDE, open the HTML page, and check that the control's
WIDTH and HEIGHT attributes in its OBJECT tag are big enough
- An OCX can contain more than one control
- The project's name is the name given to the OCX file when compiled;
A control's name is the right hand-side part in the ProgID, ie. myproject.myctrl;
The description (Project | Properties | Description) is the string that
shows up when listing the registered components on a host. So, choose those
three infos carefully
Step-by-step procedure to write, compile, and upload an ActiveX control
Running an ActiveX control implies that a few components be installed once
and for all before this control, such as the VB run-time, Automation, etc. As
of now, just install the VB IDE on the client host where you wish to test this
first sample; We'll see later how to package your application so that it installs
on a bare host through a CAB archive.
For security reasons, by default, IE is set up to either prompt the user,
or simply forbird downloading ActiveX controls. The solution is to add the domain
or host in the list of Trusted Sites (Tools | Internet Options, Security tab),
and lower the security settings for those sites by clicking on the "Custom
Level..." button.
- Create a new ActiveX Control project, and build a new ActiveX Control with just a pushbutton
called Command1 that displays a message box when clicked
- Make sure the version number is increased every time your recompile:
Select Project | Properties, click on the Create tab, and check the "Automatic
increment" option. You'll just need to update this information in the web
page so that the client knows that a new version of the ActiveX component
is available on the server
- Compile this ActiveX control
- Go back to the Project | Properties dialog, select the
Component tab, choose "Binary compatibility", and aim at dummy.ocx.
This makes sure that from now on, the control's CLSID remains identical every time you
recompile the control, so you don't have to find and copy/paste the new
CLSID in the web page
- On the web server, create a directory to store this OCX and the HTML
page where it will be referenced
- Upload this ActiveX component in this directory
- In the same directory where you saved the ActiveX, create a web page
eg. index.html with the following content:
<HTML>
<HEAD>
<TITLE>Testing
ActiveX</TITLE>
</HEAD>
<BODY>
<OBJECT ID="UserControl11"
CLASSID="CLSID:67A2A38D-3CA7-479A-9928-C4E070A691EE"
CODEBASE="dummy.ocx#version=1,0,0,3">
</OBJECT>
<script
language="vbscript">
Call
UserControl11.command1.click
</script>
</BODY>
</HTML>
To
find out what the CLSID is for the component, either search the Registry
on the host where the component was compiled (look for dummy.ocx), or launch
the Microsoft ActiveX Control Pad, and insert this component into the page,
which will tell you its CLSID. To find out the version number of the component,
either launch Windows Explorer, right-click on the .OCX file, and hit the Version
tab, or look in the Project | Properties, followed by the Create tab.
Since the CLSID remains the same every time you compile the
ActiveX component (thanks to binary compatibility), the only way for the
client host to know that a newer version of the component is available on
the server is by checking the release number given above in the CODEBASE
attribute. In other words, if you recompile and upload your ActiveX
component but forget to update this information in the web page, the client
host will not download the new version and continue running the previous
version that is already located locally.
Incidently, since the server
does not use the Registry to locate the control, this also means that you
do not have to run Windows + IIS to host a web page that links to an ActiveX
control, but could just as well run Apache on a Unix server...
Note that you could just as well write the ActiveX component to display a
message box when the user clicks on the command1 button. I included this little
bit of VBS just to show you how VBS and ActiveX components can work together.
- If you compiled this component on the same host where you wish to perform
a test, make sure you uninstall the component from this host (otherwise,
the new version won't be downloaded since the client host already has it
installed): Open a DOS box, and run "regsrv32 c:\path\to\ocx\dummy.ocx
/u" : The component is now removed from the client host. Obviously,
you really should test on a bare host that never had VB-related stuff on
it as this is the only way to make sure a client host downloads all the
stuff it needs to run this web application
- Aim your browser at http://server/index.html and check that the control
is correctly downloaded and run
Signing controls with Microsoft Authenticode
Starting with XPSP2, it appears that ActiveX controls will no longer be downloaded
through a web page unless they've been signed with Authenticode:
"You will need to apply for and receive either an Individual or Commercial
Software Publisher certificate from a Certificate Authority (CA) that supports
Authenticode™ technology. "Digital Certificates for Authenticode"
provides more information about the certificate enrollment process for software
publishers. Digital IDsSM for Software Publishers is now available from VeriSign."
Updating OCX's
Here's a way to update OCX's from your web server:
- 1. Have an Setting in the registry for the control version.
- 2. Have a centrally located Controls.ini file.
- 3. Whenever the versions don't match in the controls file, copy the
.OCX to the local computer.
- 4. Register the control.
-
- Your Done.
-
- Now for what you really want.
-
- TS1 = GetSetting(App.Title, "Control Information", "IntakeManage",
"-2") ' Get control info from the registry.
- TS = Space(16)
- RetVal = GetPrivateProfileString("Control Information", "IntakeManage",
"-1", TS, 16, MPath + "Controls.ini") ' get control
info from the .ini file.
- TS = left(TS, RetVal)
- If TS <> TS1 Then ' We need an update
- If Onsite Then
- Err.Clear
- On Error Resume Next
- FileCopy Directory & "IntakeManage.ocx", SysDir &
"IntakeManage.ocx" ' Copy the control
- If Err Then
- MsgBox "Unable to update Intake Control. Please exit out of any
copy of Zonecare and try again."
- End
- End If
- Shell "regsvr32 /s " & SysDir & "IntakeManage.ocx",
vbHide ' register the control
- SaveSetting App.Title, "Control Information", "IntakeManage",
TS ' update the registry
- End If
- End If
-
-
- NOTE: This code must be placed in a sub main and sub Main must be your
startup. Otherwise, your main form might have one of the controls on it
and the control will not get updated.
List of attributes
Here's the list of attributes that can be used in the OBJECT tag:
- border: width of the border for an object used as hyperlink
- classid: unique ID to an ActiveX control. This is the minimum attribute
that you must include, along with the codebase attribute so your browser
knows from where it can download this control if it is not installed on
the client host. Once a control has been registered on a host, its CLSID
can be found in the Registry at HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID
.
This attribute can also include the VIEWASTEXT
switch.
- codebase: location where the control can be found on the server.
Required if the control has never been installed on the client host.
This
attribute can/should be followed by a "version" attribute, so
the browser can tells whether a newer version of the control is available
on the server. The whole syntax looks like CODEBASE="dummy.ocx#version=1,0,0,3".
You can force update every time a user browses the page by using "version=-1,-1,-1,-1".
Note that any object that has a version number (and possibly a CLSID) can
be mentionned here (ie. OCX, DLL, EXE, CAB).
Ideally,
the version number should be updated in both the web page and the INF file
contained in the CAB archive (in case you are using CAB archives instead
of direct links to OCX files to distribute your controls), but if you're
lazy, just updating the version number in the CODEBASE attribute is enough
to trigger a new download
- codetype: specifies a MIME type
- data: URL where a control's data can be downloaded
- declare: tells the browser to load a control without activating it
- height: height of a control, in pixels
- hspace: horizontal space between the control and surrounding text
- id: gives a name to the control, which you can use to access it from
VBScript code. Optional.
- name: gives a name to a control, which can be used to refer to it in
an HTML form
- shapes: contains geometric forms to be used as hyperlink
- standby: text displayed while a control is being downloaded (eg. "Please
wait while this ActiveX control is being downloaded...") Doesn't
seem to work
- type: specifies the type of data specified by the "data" attribute,
eg. "application/x-oleobject"
- usemap: connects an object to an array of links
- vspace: vertical space betwwen the control and surrounding text
- width: width of a control, in pixels
(CHECK) Note the INF files are
read "from the bottom up" when you list the dependent files (it
took me a bunch of sweat to find this out..)
Building a CAB using VB's Deployment Wizard
This is by far the easiest way to get started, as the wizard will build all
the files you need to build a CAB and the HTML file where lives the OBJECT tag
that points to the ActiveX control you want to distribute. Once VB5 is installed,
this wizard can be found at c:\Program Files\DevStudio\VB\setupkit\kitfil32\Setupwiz.exe
.
- Launch the wizard, and choose the control's VBP file
- Select "Build Internet package", and follow the instructions.
Any OCX on which your control depends on that does not have a DEP file will
trigger a warning, since the wizard is unable to check its own dependencies
(don't ask why the wizard can't look inside the an OCX, DLL, or EXE to search
for dependencies directly...)
- Once the wizard is done, you will be provided by an HTML file which
contains an OBJECT tag referencing this ActiveX control, a CAB file which
contains this OCX along with other, non-MS controls and DLLs it depends
on (optional), and an INF file which lists the dependencies, and how to
solve them (ie. where to download VB's run-time stuff from MS' web site,
if you chose to let the user fetch those from MS' site instead of your own).
You are also provided with a Support/ sub-directory, which contains a copy
of each of those non-MS dependencies, the INF file, and a DDF file. Use
the DDF file to build a CAB manually, using the command-line MAKECAB.EXE
utility provided with VB
Notes:
- In case your ActiveX control makes use of other ActiveX controls, those
must have a .DEP file, which lists the files they themselves depend on.
Use the Deployment Wizard to generate a DEP file.
- Those extra ActiveX controls must be registered; Copying them in the
same directory where your project files live is not enough. Just like any
ActiveX control, the wizard looks up a control in the Registry. Note that
if another version of a given OCX is also available in WINDOWS' directory
but is not the one registered, the wizard will warn you (ie., any OCX that
your control depends on will be looked for in WINDOWS instead of just depending
on the Registry)
- In case your project makes use of regular DLLs (ie. non-COM), they must
be located in directories where the wizard can find them: Either in the
same directory where your VBP file lives, C:\WINDOWS, \SYSTEM[32], or any
directory specified in the PATH variable
- If your ActiveX control includes the Microsoft Calendar OCX, its DEP
file is often wrong: Register=$(DLLSelfRegister
Ex)
and Version=8.0.0.5007
- Check what happens on W2K/XP when a CAB updates Windows system files
while the user is not logged with administrative rights
- Once you have used the Wizard to build a working CAB and HTML files,
you can use MAKECAB.EXE with the DDF and INF files to build a new CAB file
yourself
Building a CAB file manually using MAKECAB.EXE
Once you have run VB's deployment wizard once, you are provided with an INF
and DDF files, which are all you need to build a new CAB file yourself. Any
time you compile a new version of your OCX, you must update its version number
if the INF, and launch MAKECAB.EXE to generate a new CAB file. Editing the DDF
file is only required if you wish to add a new file to the CAB; If this new
file is an OCX, you are better off asking the deployment wizard to generate
the INF for you, as an ActiveX control has a bunch of dependencies (in other
words, edit the DDF file manually to add non-OCX stuff, eg. regular DLLs, EXEs,
and non-executable files.)
- If you need to add a new file to the CAB, edit your DDF file
- Edit the INF file to update your OCX's version number (and add relevant
sections if you are adding extra files)
- makecab /F myfile.ddf
- del setup.rpt
Voilà! You are now the proud owner of a new CAB :-) You are
Determining dependencies
Besides the fixed-cost components like the VB run-time or Automation, your
application probably needs additional components to run. Unfortunately, I don't
know of a free tool to build a list automatically, so here's how to do this:
- Use VB's PDW to generated a DEP file for each of your OCX. This DEP
file contains all the dependencies for a given ActiveX control
- Read the project's VBP
- Any DLL referenced by a VB project should be added to the list of dependencies,
so look for DECLARE statements
Running EXEs out of an INF/CAB
According to a message
crossposted to some microsoft.* newsgroups, it may be possible to run an EXE
to install stuff through an INF/CAB. I don't know how to make sure it runs silently,
and in which order (order of appearance in INF?)
Sample VB5 INF File
Here's a DUMMY.CAB which contains an bare DUMMY.OCX to trigger the download
of the CAB. The CAB contains a number of components that are shared by the different
web apps I wrote.
The way things I organized things on my web server:
- index.php contains a welcome screen, explaining to users that they need
to lower security settings in IE and accept a few fixed-cost components;
- Next, we move to install.php which contains the DUMMY.OCX section so
IE downloads the corresponding CAB file whose INF is shown below.
- Once those fixed-cost components are installed (and won't need to be
downloaded again until you make a change to the OCX/CAB), we move on to
menu.php, which contains links to the different applications, each consisting
in a single OCX, since all the other components have already been installed
through DUMMY.CAB.
- ;INF file located in DUMMY.CAB linked to DUMMY.OCX
- ;DestDir can be 10 for \Windows, 11 for Windows\System(32) or left blank
to mean Occache
-
- [version]
- signature="$CHICAGO$"
- AdvancedINF=2.0
-
- [Add.Code]
- DUMMY.OCX=DUMMY.OCX
-
- ;Common Controls 5.0 SP2 - Includes advanced controls like progress
bar, etc.
- COMCTL32.OCX=COMCTL32.OCX
-
- ;Common Controls2 6.0 SP4 - Contains DatePicker etc.
- MSCOMCT2.OCX=MSCOMCT2.OCX
-
- ;Localized (French) file
- MSCC2FR.DLL=MSCC2FR.DLL
-
- ;VB5-compatible version of SQLite
- PSVBUTLS32.DLL=PSVBUTLS32.DLL
-
- ;Localized (French) file
- CMCTLFR.DLL=CMCTLFR.DLL
-
- ;ComponentOne's VSFlexGrid
- VSFLEX7L.OCX=VSFLEX7L.OCX
-
- ;VB fixed-cost stuff
- ASYCFILT.DLL=ASYCFILT.DLL
- MSVBVM50.DLL=MSVBVM50.DLL
-
- ;Localized (French) file
- VB5FR.DLL=VB5FR.DLL
-
- ;Common Controls 6.0SP4 - Includes advanced controls like progress bar,
image combo, etc.
- MSCOMCTL.OCX=MSCOMCTL.OCX
-
- ;Common Dialogs
- COMDLG32.OCX=COMDLG32.OCX
-
- ;Localized (French) file
- CMDLGFR.DLL=CMDLGFR.DLL
-
- ;Localized (French) file
- MSCMCFR.DLL=MSCMCFR.DLL
-
- [DUMMY.OCX]
- file-win32-x86=thiscab
- RegisterServer=yes
- clsid={BAF08E86-0ED3-473B-B8F7-6118840E738B}
- DestDir=10
- FileVersion=1,0,0,0
-
- [COMCTL32.OCX]
- hook=ComCtl32.cab_Installer
- clsid={9ED94440-E5E8-101B-B9B5-444553540000}
- FileVersion=6,0,81,5
-
- [ComCtl32.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb5/ComCtl32.cab
- InfFile=ComCtl32.inf
-
- [MSCOMCT2.OCX]
- hook=MSComCt2.cab_Installer
- clsid={B09DE715-87C1-11D1-8BE3-0000F8754DA1}
- FileVersion=6,0,88,4
-
- [MSComCt2.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb6/MSComCt2.cab
- InfFile=MSComCt2.inf
-
- [MSCC2FR.DLL]
- hook=MSCc2FR.cab_Installer
- FileVersion=6,0,81,63
-
- [MSCc2FR.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb6/MSCc2FR.cab
- InfFile=MSCc2FR.inf
-
- [PSVBUTLS32.DLL]
- file-win32-x86=thiscab
- RegisterServer=no
- DestDir=10
-
- [CMCTLFR.DLL]
- hook=CmCtlFR.cab_Installer
- FileVersion=6,0,80,22
-
- [CmCtlFR.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb5/CmCtlFR.cab
- InfFile=CmCtlFR.inf
-
- [VSFLEX7L.OCX]
- file-win32-x86=thiscab
- RegisterServer=yes
- clsid={C0A63B86-4B21-11d3-BD95-D426EF2C7949}
- DestDir=10
- FileVersion=7,0,0,62
-
- [ASYCFILT.DLL]
- hook=AsycFilt.cab_Installer
- FileVersion=2,20,4118,1
-
- [AsycFilt.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb5/AsycFilt.cab
- InfFile=AsycFilt.inf
-
- [MSVBVM50.DLL]
- hook=MSVBVM50.cab_Installer
- FileVersion=5,2,82,44
-
- [MSVBVM50.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb5/MSVBVM50.cab
- InfFile=MSVBVM50.inf
-
- [VB5FR.DLL]
- hook=VB5FR.cab_Installer
- FileVersion=5,0,43,19
-
- [VB5FR.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb5/VB5FR.cab
- InfFile=VB5FR.inf
-
- [MSCOMCTL.OCX]
- hook=MSComCtl.cab_Installer
- clsid={1EFB6596-857C-11D1-B16A-00C0F0283628}
- FileVersion=6,0,88,62
-
- [MSComCtl.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb6/MSComCtl.cab
- InfFile=MSComCtl.inf
-
- [COMDLG32.OCX]
- hook=ComDlg32.cab_Installer
- clsid={F9043C85-F6F2-101A-A3C9-08002B2F49FB}
- FileVersion=6,0,84,18
-
- [ComDlg32.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb6/ComDlg32.cab
- InfFile=ComDlg32.inf
-
- [CMDLGFR.DLL]
- hook=CmDlgFR.cab_Installer
- FileVersion=6,0,81,63
-
- [CmDlgFR.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb6/CmDlgFR.cab
- InfFile=CmDlgFR.inf
-
- [MSCMCFR.DLL]
- hook=MSCmCFR.cab_Installer
- FileVersion=6,0,81,63
-
- [MSCmCFR.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb6/MSCmCFR.cab
- InfFile=MSCmCFR.inf
Sample VB6 INF file
This is the INF file generated by VB6's add-in utility "Packaging and
Deployment Utility" to distribute a single, no thrill ActiveX control (ie.
not extended controls, just basics like a label and a push-button):
- ;DestDir can be either 10 for \Windows, 11 for Windows\System(32) or
empty for Occache
-
- [version]
- signature="$CHICAGO$"
- AdvancedINF=2.0
-
- [DefaultInstall]
- CopyFiles=install.files
- RegisterOCXs=RegisterFiles
- AddReg=AddToRegistry
-
- [RInstallApplicationFiles]
- CopyFiles=install.files
- RegisterOCXs=RegisterFiles
- AddReg=AddToRegistry
- [DestinationDirs]
- install.files=11
-
- [SourceDisksNames]
- 1=%DiskName%,dummy.CAB,1
-
- [Add.Code]
- dummy.ocx=dummy.ocx
- MSSTKPRP.DLL=MSSTKPRP.DLL
- MSPRPFR.DLL=MSPRPFR.DLL
- msvbvm60.dll=msvbvm60.dll
- OLEAUT32.DLL=OLEAUT32.DLL
- OLEPRO32.DLL=OLEPRO32.DLL
- ASYCFILT.DLL=ASYCFILT.DLL
- STDOLE2.TLB=STDOLE2.TLB
- COMCAT.DLL=COMCAT.DLL
- VB6FR.DLL=VB6FR.DLL
-
- [install.files]
- dummy.ocx=dummy.ocx
-
- [SourceDisksFiles]
- dummy.ocx=1
-
- [dummy.ocx]
- file-win32-x86=thiscab
- RegisterServer=yes
- clsid={F4C9FFFC-7C1F-4C22-9507-CD8F7A160952}
- DestDir=
- FileVersion=1,0,0,3
-
- [MSSTKPRP.DLL]
- hook=MSSTKPRP.cab_Installer
- FileVersion=6,0,81,69
-
- [MSSTKPRP.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb6/MsStkPrp.cab
- InfFile=MsStkPrp.inf
-
- [MSPRPFR.DLL]
- hook=MSPRPFR.cab_Installer
- FileVersion=6,0,81,63
-
- [MSPRPFR.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb6/MsPrpFR.cab
- InfFile=MsPrpFR.inf
-
- [msvbvm60.dll]
- hook=msvbvm60.cab_Installer
- FileVersion=6,0,89,64
-
- [msvbvm60.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb6/VBRun60.cab
- run=%EXTRACT_DIR%\VBRun60.exe
-
- [OLEAUT32.DLL]
- hook=OLEAUT32.cab_Installer
- FileVersion=2,40,4275,1
-
- [OLEAUT32.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb6/VBRun60.cab
- run=%EXTRACT_DIR%\VBRun60.exe
-
- [OLEPRO32.DLL]
- hook=OLEPRO32.cab_Installer
- FileVersion=5,0,4275,1
-
- [OLEPRO32.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb6/VBRun60.cab
- run=%EXTRACT_DIR%\VBRun60.exe
-
- [ASYCFILT.DLL]
- hook=ASYCFILT.cab_Installer
- FileVersion=2,40,4275,1
-
- [ASYCFILT.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb6/VBRun60.cab
- run=%EXTRACT_DIR%\VBRun60.exe
-
- [STDOLE2.TLB]
- hook=STDOLE2.cab_Installer
- FileVersion=2,40,4275,1
-
- [STDOLE2.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb6/VBRun60.cab
- run=%EXTRACT_DIR%\VBRun60.exe
-
- [COMCAT.DLL]
- hook=COMCAT.cab_Installer
- FileVersion=4,71,1460,1
-
- [COMCAT.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb6/VBRun60.cab
- run=%EXTRACT_DIR%\VBRun60.exe
-
- [VB6FR.DLL]
- hook=VB6FR.cab_Installer
- FileVersion=6,0,89,88
-
- [VB6FR.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb6/VB6FR.cab
- InfFile=VB6FR.inf
-
- [Setup Hooks]
- AddToRegHook=AddToRegHook
-
- [AddToRegHook]
- InfSection=DefaultInstall2
-
- [DefaultInstall2]
- AddReg=AddToRegistry
-
- [AddToRegistry]
- HKLM,"SOFTWARE\Classes\CLSID\{F4C9FFFC-7C1F-4C22-9507-CD8F7A160952}\Implemented
Categories\{7DD95802-9882-11CF-9FA9-00AA006C42C4}"
- HKLM,"SOFTWARE\Classes\CLSID\{F4C9FFFC-7C1F-4C22-9507-CD8F7A160952}\Implemented
Categories\{7DD95801-9882-11CF-9FA9-00AA006C42C4}"
- HKCR,"Licenses",,,"Licensing: Copying the keys may be
a violation of established copyrights."
-
- [RegisterFiles]
- %11%\dummy.ocx
My application requires more files than just one ActiveX control
VB5 and 6 provide a setup wizard to build a CAB file, which is the equivalent
of a ZIP file with the addition of an INF file to provide extra information
on each file that make up this packaged file. For VB5, this wizard is located
on the CD at VB\SETUPKIT\KITFIL32\SETUPWIZ.EXE. Once you have this wizard once,
a DDF file is generated that you can modify as you wish and then use as input
to the Makecab.exe utility to regenerate a CAB file manually.
Here's how to include JPG files in the CAB file, and have those files downloaded
into the user's Windows directory:
- [Add.Code]
- DUMMY.OCX=DUMMY.OCX
- DUMMY.JPG=DUMMY.JPG
-
- [DUMMY.JPG]
- file-win32-x86=thiscab
- RegisterServer=no
- ;10 = Drive:\WINDOWS (or WINNT), 11 = WINDOWS\SYSTEM, empty = WINDOWS\Downloaded
Program Files\
- DestDir=10
- FileVersion=
For your information, you cannot use a dummy CLSID to use a CAB to distribute
non-OCX files; Doing so triggers a download of the stuff listed in the INF every
time the page is viewed. A work-around is to build a small OCX that does nothing,
and include it in the HTML page, the INF, and the CAB. Needless to say, should
you make any change to the contents of the CAB file (ie. add some DLL), you
must update the dummy OCX in order for IE to trigger a new download.
Before performing a new test, remember to remove the OCX in the Registry,
and delete all the downloaded files in the Windows directory that make up this
CAB file. Better yet, use a bare test host, ghost it, and build a bunch of images
that you can reinstall in a couple of minutes using cloning software like Ghost,
DriveImage, et al.
More infos:
INF sections for common dependencies
Here's the relevant sections that must be located in an INF so that IE knows
what to do if it encounters an ActiveX control that depends on other controls
which are either not available on the host, or with an older version number.
Note that you need more sections if you use localized controls (eg. the Common
Dialog widget requires a couple of extra sections for the language you used.)
Microsoft Windows Common Control 5.0 SP2
Progress bar, etc.
- [COMCTL32.OCX]
- hook=ComCtl32.cab_Installer
- clsid={9ED94440-E5E8-101B-B9B5-444553540000}
- FileVersion=6,0,81,5
-
- [ComCtl32.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb5/ComCtl32.cab
- InfFile=ComCtl32.inf
Microsoft Windows Common Control 6.0 SP4
Same as 5.0 SP2, but with a couple of additional controls like Image Combo
- [MSCOMCTL.OCX]
- hook=MSComCtl.cab_Installer
- clsid={1EFB6596-857C-11D1-B16A-00C0F0283628}
- FileVersion=6,0,88,62
-
- [MSComCtl.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb6/MSComCtl.cab
- InfFile=MSComCtl.inf
Microsoft Windows Common Control-2 6.0 SP4
DatePicker, etc.
- [MSCOMCT2.OCX]
- hook=MSComCt2.cab_Installer
- clsid={B09DE715-87C1-11D1-8BE3-0000F8754DA1}
- FileVersion=6,0,88,4
-
- [MSComCt2.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb6/MSComCt2.cab
- InfFile=MSComCt2.inf
Microsoft Common Dialog Control 6.0 SP3
Common dialog boxes like OpenFile, etc.
- [COMDLG32.OCX]
- hook=ComDlg32.cab_Installer
- clsid={F9043C85-F6F2-101A-A3C9-08002B2F49FB}
- FileVersion=6,0,84,18
-
- [ComDlg32.cab_Installer]
- file-win32-x86=http://activex.microsoft.com/controls/vb6/ComDlg32.cab
- InfFile=ComDlg32.inf
Chains of events
Here's the order in which events are triggered when loading an ActiveX control
in a web page:
- Initialize
- InitProperties (which can be changed through the PARAM tag in the web
page). ReadProperty is called instead if some elements were stocked using
the PropertyBag object?
- Resize (for native controls)/Paint (for user-drawn controls)
- Show ?
- Other events...
- WriteProperty if the PropertyChanged property is set?
- Terminate
List of events
AccessKeyPress
Se produit lorsque l’utilisateur du contrôle appuie sur l’une des touches
d’accès rapide du contrôle ou lorsque la touche ENTRÉE est
actionnée alors que le développeur a affecté à la
propriété Default la valeur True, ou, lorsque la touche ÉCHAP
est actionnée alors que le développeur a affecté à
la propriété Cancel la valeur True. Les propriétés
Default et Cancel sont activées par le concepteur du contrôle en
affectant à la propriété DefaultCancel la valeur True.
AmbientChanged
Se produit lorsque la valeur d’une propriété ambiante change.
AsyncReadComplete
Se produit lorsque le conteneur a accompli une requête de lecture asynchrone.
Click
DblClick
DragDrop
Se produit à la fin d'une opération glisser-déplacer
soit parce que l'utilisateur a fait glisser un contrôle sur un objet et
a relâché le bouton de la souris, soit parce que la valeur 2 (Drop)
a été affectée à l'argument action de la méthode
Drag utilisée.
DragOver
Se produit lorsqu'une opération glisser-déplacer est en cours.
Vous pouvez utiliser cet événement pour contrôler le pointeur
de la souris lorsqu'il aborde ou quitte une cible valide ou s'immobilise dessus.
La position du pointeur de la souris détermine l'objet cible qui reçoit
l'événement.
EnterFocus
Se produit lorsque le focus atteint l’objet. Le focus peut être reçu
par l’objet lui-même ou par un contrôle constitutif.
ExitFocus
Se produit lorsque le focus quitte l’objet sur lequel il était. Le
focus peut être perdu par l’objet lui-même ou par un contrôle
constitutif.
GotFocus
Se produit dans l’objet ou dans le contrôle constitutif lorsque le
focus y parvient. L’objet défini par l'espace réservé object
ne peut obtenir le focus que si la propriété CanGetFocus a la
valeur True et qu’aucun des contrôles constitutifs ne peut recevoir le
focus. L’événement EnterFocus survient avant l’événement
GotFocus.
Hide
Se produit lorsque la propriété Visible de l’objet prend la
valeur False.
Initialize
Se produit lorsqu'une application crée une instance d'un objet Form,
MDIForm, UserControl, PropertyPage, ou d'une classe. Faites appel à cet
événement pour initialiser les données utilisées
par l'instance de l'objet Form ou MDIForm, ou de la classe. Dans le cas
de ces objets, l'événement Initialize se produit avant l'événement
Load (ATTENTION : Load() N'EXISTE PAS POUR DES CONTROLES!)
InitProperties
Se produit lorsqu’une nouvelle instance d’un objet est créée.
Cet événement permet au concepteur de l’objet d’initialiser
une nouvelle instance de cet objet. Cet événement n’intervient
qu’en cas de création d’une nouvelle instance d’un objet. Ainsi, le concepteur
de l’objet peut faire la distinction entre la création d’une nouvelle
instance de l’objet et le chargement d’une instance existante de ce même
objet.
En plaçant un code initialisant de nouvelles instances d’un objet
dans l’événement InitProperties plutôt que dans l’événement
Initialize, le développeur peut éviter les situations où
le fait de charger des données dans une instance existante de l’objet,
par le biais d’un événement ReadProperties, annule l’initialisation
de ce même objet.
KeyDown
KeyUp
LostFocus
Se produit dans l’objet ou dans le contrôle constitutif lorsque le
focus le quitte. L’événement LostFocus survient avant l’événement
ExitFocus.
MouseDown
MouseMove
MouseUp
OLECompleteDrag
OLEDragDrop
OLEDragOver
OLEGiveFeedBack
OLESetData
OLEStartDrag
Paint
L'événement Paint est invoqué lorsque la méthode
Refresh est utilisée. Si la propriété AutoRedraw a la valeur
True, les données sont automatiquement réaffichées, de
sorte que l'événement Paint n'est pas nécessaire.
Le fait d'utiliser la méthode Refresh dans une procédure d'événement
Resize provoque le réaffichage complet de l'objet chaque fois que l'utilisateur
redimensionne la feuille.
ReadProperties
Se produit lors du chargement d’une instance existante d’un objet dont l’état
a été enregistré.
Lorsque cet événement intervient, le concepteur de l’objet
peut charger l’état enregistré à partir de l’argument pb,
en invoquant la méthode ReadProperty de l’objet PropertyBag pour chaque
valeur devant être chargée. Cet événement intervient
après l’événement Initialize.
Prévoyez toujours un mécanisme de détection d’erreurs
lorsque vous manipulez l’événement ReadProperties. Vous protégerez
ainsi le contrôle contre les valeurs de propriétés invalides
susceptibles d’avoir été entrées par les utilisateurs qui
auront modifié le fichier contenant les données enregistrées
avec des éditeurs de texte. Veillez cependant à ne pas déclencher
une erreur dans un événement, ce qui serait fatal au conteneur.
Un mécanisme de détection d’erreurs intégré à
la procédure de l’événement ReadProperties ne doit donc
en aucun cas générer d’erreurs.
Resize
Si vous souhaitez que la taille des graphiques reste proportionnelle à
celle de la feuille après son redimensionnement, invoquez l'événement
Paint en utilisant la méthode Refresh dans une procédure d'événement
Resize.
Lorsque la propriété AutoRedraw a la valeur False et que la
feuille est redimensionnée, Visual Basic appelle également les
événements connexes Resize et Paint, dans cet ordre. Lorsque vous
associez des procédures à ces événements connexes,
veillez à ce que leurs actions ne soient pas en conflit.
Lorsque la propriété SizeMode d'un contrôle conteneur
OLE a la valeur 2 (Autosize), le contrôle est automatiquement redimensionné
selon la taille d'affichage de l'objet qu'il contient. Si cette taille change,
le contrôle est automatiquement ajusté à la taille de l'objet.
Dans ce cas, l'événement Resize est invoqué pour l'objet
avant que le contrôle conteneur OLE soit redimensionné. Les arguments
height et width indiquent la taille optimale d'affichage de l'objet (déterminée
par l'application qui a servi à le créer). Vous pouvez affecter
une taille différente à l'objet en modifiant les valeurs des arguments
height et width de l'événement Resize.
Show
Se produit lorsque la propriété Visible de l’objet prend la
valeur True. Si le contrôle est en cours d’affichage dans un explorateur
Internet, un événement Show se déclenche si l’utilisateur
revient à la page contenant le contrôle.
Terminate
Se produit lorsque toutes les références à une instance
d'un objet Form, MDIForm, UserControl, PropertyPage ou d'une classe sont supprimées
de la mémoire soit parce que la valeur Nothing a été affectée
à toutes les variables faisant référence à l'objet,
soit parce que la dernière référence à l'objet est
hors de portée.
Pour tous les objets à l'exception des classes, l'événement
Terminate se produit après l'événement Unload.
L'événement Terminate n'est pas déclenché si
les instances de la feuille ou de la classe ont été supprimées
de la mémoire en raison d'un arrêt anormal de l'application. Par
exemple, si votre application invoque l'instruction End avant d'avoir supprimé
de la mémoire toutes les instances existantes de la classe ou de la feuille,
l'événement Terminate n'est pas déclenché pour la
feuille ou la classe considérée.
WriteProperties
Se produit lorsqu’une instance d’un objet doit être enregistrée.
Cet événement signale à l’objet que son état doit
être enregistré de manière à pouvoir être restauré
ultérieurement. Dans la plupart des cas, l’état de l’objet est
uniquement constitué de valeurs de propriétés.
Le concepteur de l’objet défini par l'espace réservé
object peut faire en sorte que celui-ci enregistre son état à
l’occasion de l’événement WriteProperties, en invoquant la méthode
WriteProperty de l’objet PropertyBag pour chaque valeur devant être enregistrée.
Note Le groupe de propriétés pb peut être
différent de l’objet pb communiqué au dernier événement
ReadProperties survenu.
L’événement WriteProperties peut intervenir plusieurs fois
au cours de l’existence d’une instance de l’objet défini par l'espace
réservé object.
Using the Property Bag
- <HTML><BODY>
<OBJECT
classid='clsid:14A2B8E1-EF77-4C43-9756-BA8F3950883D' STANDBY='Loading....'>
<PARAM NAME='MyHello' VALUE="Hello">
</OBJECT>
Public Sub UserControl_Initialize()
End Sub
Public Property
Get MyHello() As String
MyHello = lblHello.Caption
End Property
Public Property Let MyHello(ByVal New_MyHello As String)
lblHello.Caption() = New_MyHello
PropertyChanged "MyHello"
End
Property
'Load property values from storage
Private Sub
UserControl_ReadProperties(PropBag As PropertyBag)
lblHello.Caption =
PropBag.ReadProperty("MyHello", "Nothing Here")
End Sub
'Write
property values to storage
Private Sub UserControl_WriteProperties(PropBag
As PropertyBag)
Call PropBag.WriteProperty("MyHello", lblHello.Caption,
"Nothing Here")
End Sub
List of changes
This is the changes made to a W2K host after adding an entry in IE's list
of Trusted Sites, and having the CAB archive download and install the prerequired
VB stuff through the embedded dummy.inf file before running an ActiveX control
(Projet1.ocx). Stuff ADDED or UPDATED.
Note that Windows at least since 98 comes with MSVBVM5 (2K and XP also have
MSVBVM6) and ASYCFILT, but those files will be upgraded if newer versions are
available on Microsoft's site (if you write your INF to tell IE to fetch those
from Microsof's site instead of your web server.)
C:\WINNT
Downloaded Program Files
system32
- MSPRPfr.DLL
- MSSTKPRP.DLL
- PSVBUTLS32.DLL (VB-compatible version of SQLite)
- VB6fr.DLL
- msvbvm60.dll
- setupapi.log
system32\config
- SECURITY
- software
- system
- SYSTEM.ALT
Security
Security-related sections in Internet Explorer are confusing:
Security tab:
- Looks like the Internet context is used when the user accesses a URL
that is not mentioned in the other sections (Local Intranet, Trusted Sites,
Restricted Sites.) Note that the Local Intranet section lets you add servers
in your organization (foreign servers should be set to Trusted Sites, instead).
- For each context, you can either use default security settings or customize
them
- The ActiveX-related security settings are
- ActiveX controls and plug-ins:
- Download signed ActiveX controls
- Download unsigned ActiveX controls
- Initialize and script ActiveX controls not marked as safe
- Run ActiveX controls and plug-ins
- Script ActiveX controls marked safe for scripting
Content tab:
This is where you manage certificates used to sign ActiveX controls.
More infos in Chapter 5
- Understanding Authentication and Security.
Digital Signing for ActiveX ComponentsLicensing
Licensing Issues for Controls
The License Package Authoring Tool won't create an
entry in the .lpk file for your ActiveX control unless you check the Required
License Key checkbox in the Project Options dialog of your control project.
The
license file is an .lpk file you associate with one or more HTML
pages. It contains license strings for each ActiveX control on the pages to
which it refers. You use the License Package Authoring Tool to create an
appropriate license file for their pages. This tool, which is available in the
Tools directory, presents you with a list of controls you can include in you
license file.
You must embed an object called the license manager in the Web page from
which a user will download your ActiveX controls. The license manager uses an
OBJECT tag to reference the control's .lpk file. If you use the Package and
Deployment Wizard to create your download, it produces the license manager and
inserts it in the file for you.
When you add
licensing support to your control component, a license key is compiled into it.
This key covers all the controls in the component. Running your Setup program transfers the license key to another computer's
registry, allowing your controls to be used for development. Simply copying your
.ocx file to another computer and registering it does not transfer the license
key, so the controls cannot be used.
When you make the .ocx file, Visual Basic will create a .vbl file containing the
registry key for licensing your control component. When you use the Package and
Deployment wizard to create a setup for your .ocx, the .vbl file is
automatically included in the setup procedure.
The license file is an .lpk file you associate with one or more HTML
pages. It contains license strings for each ActiveX control on the pages to
which it refers. You use the License Package Authoring Tool to create an
appropriate license file for their pages. This tool, which is available in the
Tools directory, presents you with a list of controls you can include in you
license file.
<!-- If any of the controls on this page require licensing, you must create a license package file. Run LPK_TOOL.EXE in the Tools directory to create the required .lpk file.
-->
<OBJECT CLASSID="clsid:5220cb21-c88d-11cf-b347-00aa00a28331">
<PARAM NAME="LPKPath" VALUE="LPKfilename.LPK">
</OBJECT>
Note: the CLASSID of the object specified for referencing the LPK file is for
the Microsoft License Manager component and not the CLSID of the components that
you are licensing!
- Each HTML page using one or more licensed controls requires a license file
(.lpk) that contains the license strings for each control.
- Each HTML page can use only a single .lpk file, but a single .lpk file can
be used for more than one page.
- The .lpk file must be on the same server as the HTML page it covers.
- The .lpk file must contain a plain text copyright notice to dissuade casual
copying of .lpk files.
Licensed controls can be used on World Wide Web pages, in conjunction with
browsers that support control licensing. Both the control component and the
license key must be available to be downloaded to the computer of the person
accessing a Web page.
The downloaded license key is not added to the registry. Instead, browser
asks the control to create a run-time instance of itself, and passes it the
downloaded license key.
The owner of the Web server that uses your control must have purchased and
installed your control, just as a developer would, in order to supply both
control and license.
If the license is not available, control creation will fail, and the browser
will receive a standard control creation error. Whether the browser passes this
message along to the person accessing the Web page, or simply ignores it,
depends on the person who developed the browser.
Things to watch out for
- With the exceptions of a control's intrisic properties like width or
height, the properties of a control are private (while methods are public,
by default.) If you need to change a control's properties from the outside,
eg. VBScript code embedded in a web page, either create a method that gives
indirect access ot its private properties, or add get/let procedures
- Add the following in the HEAD section in each page that contains an
OBJECT tag, to forbid the browser from caching the page, thus, making it
difficult to updated a control:
<meta http-equiv="Pragma"
content="no-cache">
- If you need to initialize data before a control pops up, use the UserControl_Initialize()
even instead of _Show()
- No reference to the Ambient object in Initiliaze(): At this point, your
ActiveX control hasn't been inserted into a container. Referering to Ambient
triggers error 398 "Client site not available". On the other hand,
you can use the following code in InitProperties() to check if the control
is currently in Design mode (ie. in the VB IDE) or in Running mode (ie.
running in the IDE, or in IE):
'UserMode True = Execution mode
If
Ambient.UserMode = False Then
MsgBox "UserMode"
End
If
- You can create more than one control in a VB project
- When recompiling an ActiveX control, make sure you update its version
number in the INF and the OBJECT tag in the web page that references it.
Otherwise, Internet Explorer won't dowload the newer version
- Make sure the fixed-cost stuff (eg. VB run-time DLL) that the user needs
to download from Microsoft's site matches the version of VB that you used
to build your ActiveX controls... Otherwise, your ActiveX control won't
start, and you'll be staring at a grey dot surrounded by a black square,
with the log file simply saying "Class not registered" :-)
- For testing purposes, make sure you use a brand new version of the OS,
ie. a host that never had the VB IDE installed. It's the only way to make
sure IE prompts to download the VB stuff
- In CABs, ideally, only include an INF: Since the CAB file is downloaded
every time the OCX it refers to needs to be downloaded (either because the
control is not available on the client host, or you updated its version
#), it'd be stupid to require the user to download megabytes of stuff it
already has (eg. VB's run-time stuff, which won't change for months)
- Make sure a user is always using the latest and greatest: It's a good idea
to display the version number of an OCX:
- Private Sub UserControl_Initialize()
- Label1.Caption = App.Major & "."
& App.Minor & "." & App.Revision
- End Sub
Troubleshooting
If an OCX doesn't load, first try the usual suspects:
- Check that the host has the VB runtime that matches the VB compiler
you used to build the OCX (ie. if you used VB5, make sure the host has the
VB5 runtime instead)
- Check that it also has any dependencies like localized VB stuff (eg.
VB5FR.DLL), components and references that your control uses (eg. MSCOMCTL.OCX,
etc.), any custom dependencies (eg. if you use some database engine like
Access, this will have to be installed prior to trying to load your OCX),
etc.
- Check that the server on which the web page is located is listed in
the Trusted Sites section of IE, and that IE lets the user download and
run ActiveX controls from those sites
- Check that the OBJECT section is correct:
- Make sure you included an "codebase=" attribute so that IE
knows where to download the OCX from
- If you're not using the WIDTH/HEIGHT attributes, try adding the following
parameters, as some users have reported that it solves the issue :
<PARAM
NAME="_ExtentX" VALUE="13203">
<PARAM NAME="_ExtentY"
VALUE="9260">
- Make sure the OBJECT tag is correctly closed. In this example below,
a > is missing after the version info, so the whole object will be ignored:
<object
id="myctl" CLASSID="CLSID:8FAB6C2E-8293-4A39-A9E9-29585D75AD04"
CODEBASE="dummy.ocx#version=1,0,0,3"
</object>
- Make sure the CLSID in the web page (and the INF file if you use a CAB)
actually matches the CLSID of the
ActiveX control mentionned in the OBJECT tag. A symptom of an error is that
you will be prompted by IE to download the same dependencies over and over
again, and also, a CLSID shown for a file in \WINNT\Downloaded Files instead
of a ProgID
- Make sure IE refreshes the page, instead of reading it from the cache
via Tools | Internet Options, or add the following tag in the header in
each HTML page to force IE to fetch the page from the server every time:
<meta
http-equiv="Pragma" content="no-cache">
- Check that the object runs OK when embedded in an EXE, and make sure
you have error handlers in all the routines: Uncaught errors when the control
is embedded in a web page will remain silent, and you'll be staring at the
familiar, grey, empty square :-)
If you're still stuck with a silent grey little square, here are things to
try:
- If you use a CAB file and set it up to prompt the user to download the
prerequisite files from Microsoft's site, make sure the client host's Internet
connectivy (ie. router, and DNS) works...
- Check that the contents of the CAB file is correct using the CABARC
utility, eg. cabarc | mycab.cab displays the list of files contained in
the archive (FYI, Windows Commander
knows how to open CAB files, but not write into them at least using release
4.51)
- Some users have reported that the PDW utilitysometimes miss dll's. Check
all your 'dll dependencies. Also look on you "Compile" options
- Unless specified differently in the INF file in a CAB file, by default,
ActiveX .ocx and .inf files are installed in the Windows\Downloaded Program
Files folder by default. If you wish, this location can be changed by tweaking
the Registry:
Use Registry Editor to change the "ActiveXCache"
value to the location you want in the following registry key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet
Settings
Use Registry Editor to change the "0" value to
the location you want in the following registry key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet
Settings\ActiveX Cache
NOTE: The values you enter in steps 1 and
2 must match. The new value can be a folder on a local hard disk, a Universal
Naming Convention (UNC) name, or a mapped network drive. Note that storing
ActiveX files on a network server may reduce Internet Explorer performance
because the ActiveX files must be run over the network.
- Check that customers don't have a firewall that strips ActiveX controls
on their way in...
- Ask your customers to launch Windows Explorer, go to C:\WINNT\Downloaded
Program Files\, where your CAB archives should be found, right-click on
a given object (eg. MYCTL.OBJECT1), and select Update. This doesn't always
force Windows to download the latest CAB via the CODEBASE attribute, but
it works... sometimes :-)
- Not sure about this, but maybe order in an INF makes
a difference, ie. maybe the VB fixed-cost stuff must be first or last, etc.
Experiment with a basic ActiveX and PDW to see how it generates entries
- If all else fails, two solutions to investigate: Either use the Code Download Log Viewer utility,
or follow the instructions
on how to view an error log file generated by Internet Explorer.
Another
solution that I haven't tried myself (From Simon MacArthur (simon.macarthur@union2.co.uk)):
"You could implement IObjectSafety in your controls. This basically
means that your control, if it is already registered on a machine, will
be seen as safe. This way you can run a standard setup (which I have found
much more reliable than P&D internet cab setups), and IE will
not go to the cab. If you have MSDN check that out for references for IObjectSafety.
Lot's of code there on how to do this, it is a bit tricky because you have
to create a typelib and use some fairly nasty looking API calls, but the
code is there to cut and paste. I'm starting to use this method a great
deal, because it allows me to have one control that on start up will download
others, and register them for me. This saves a huge amount of running around
creating cabs, signing them etc. My first page checks the installed versions
against an xml manifest, then downloads just the updated dlls ocx etc and
registers them for me."
Q&A
What is the relation between the four-digit version number as generated
by VB when compiling an ActiveX control, and the two-digit number that shows
up in that control's record in the Registry?
No relationship. The two-digit number reflects changes in the control's TypeLib
while maintaining binary compatibility. It's COM's way to keep more than one
interface in a given control. The alternative is to break binary compatibility,
so that older apps use the original CLSID to access the control's older interface,
while newer apps use the newer CLSID.
Some ActiveX controls from Microsoft have more than one Version entries
for a given control, such as 1.0 and 1.2. Why is that?
If there's more than one version registered, it usually means that someone
forgot to set, or forgot how to manage Binary Compatibility settings.
What are TypeLibs as opposed to CLSIDs?
A TypeLib defines the interface of the object. Adding a new interface increments
the TypeLib version. A given OCX is listed under two different GUIDs (under
HKEY_CLASSES_ROOT\CLSID\ and HKEY_CLASSES_ROOT\TypeLib\). More information on
this issue in this Binary Compatibility
primer.
Here are some apps that let you view informations on a COM control:
- ActiveX
Property Sheet Shell Extension (Lets you inspect the TypeLib's on any
ActiveX component)
- ActiveX
Documenter (A bit tricky to setup, and there's a bug or two; Contains
all the code you'd need to inspect TypeLib versions, where a component's
located on the drive (based on info found in the registry), CLSID's, TypeLib
ID's, etc, etc, etc... uses the same component as VB's Object Browser does
so....)
- Com Explorer (Very cool,
although not free; "COM Explorer is a unique tool specifically designed
to enable developers and system administrators to explore, manage and fix
ActiveX Controls, EXE Servers (Out-Proc) and DLL Servers (In-Proc).")
Is it possible to have two versions of a control in different directories,
and have them both registered and available for applications that expect either
of the two versions?
Suppose more than one version of a control is registered, how can I which
versions are installed, and load a given version?
Reading the control's record in the Registry is at least one possible way,
although there might be a COM method to achieve the same end. In the IDE, use
the Reference > Components dialog to list the different interfaces provided
by a control.
Programmatically, it seems like it's not possible to select a given version.
The only way is to unregister the one that you're not interested in and register
the other. The app will bomb if an older version is loaded.
Handling Err 429
- By Iouri Boutchkine
-
- ACTIVEX CAN'T CREATE WHICH OBJECT?
-
- When working on a large VB application that uses hundreds of COM objects,
the "429 can't create object" error doesn't give you much help
in determining which object could not be created. You can get around
this limitation by writing a function to wrap the VB runtime CreateObject
function:
-
- Public Function CreateObject(sProgID as string) as object
- On Error Goto CreateErr
- ' Call the VB runtime CreateObject function
- Set CreateObject = VBA.CreateObject(sProgId)
- Exit Function
-
- CreateErr:
- ' return the error with the name of the object
that could not be created
- Err.Raise Err.Number, _
- "CreateObject Wrapper", Err.Description
& ": '" & sProgID & "'"
- End Function
-
- With this wrapper function, you get the 429 error and the name of the
object that could not be
- created.
-
- This problem happens when you use an ActiveX control in your program
and the ActiveX control is not
- registered in the registry. If it works on the Development PC, it must
be an incompatibillity between your
- control and the same control installed in the user PC. To fix this check
which ActiveX controls you need in
- order to run your program and make sure all of them are placed in the
SYSTEM folder. You should know which control is the one that's giving
you so much trouble (it must be in the Form that crashes your program) so
you'll have to manually register it. To do it you have two basic choices:
Do it through Windows Explorer or through a DOS Prompt Window. If
you are using the Explorer just drag and drop your
- control into REGSVR32.EXE (Both must be in the SYSTEM folder) or in
the Dos Prompt window be sure you are in the SYSTEM folder and tye
REGSVR32 [YourControlName].OCX After doing this you should see a message
box saying that the registration process succeeded. If it fails, then
you will have to dig inside the registry and find all the keys that references
the control to delete them. Then you'll have to repeat the registration
process.
-
- Error 429 means that there is a component that isn't correctly registered.
The PDW is supposed to take care of this, but sometimes it forgets. I doubt
its an ADO component, just because since it is referenced in different ways
so the PDW couldn't overlook it. Does your project have any custom controls
or DLLs that were written by you or your company. These it may not pick
up and register properly. If you find that this problem is only occurring
on one machine, see if you can manually register the suspected controls
by going to the start-run menu and typing "regsvr32 <dll
or ocx path and name>". if it still doesn't work - look into
rebuilding the setup package with the PDW and examine every option
and/or another setup packager (Wise or Install Shield).
-
- Here's another clue: You are refrencing an ado library that is the latest
and geratest on your machine but when you try to package the exe PDW
by dafault picks up from its own repository of redistribution components
which normally has a version which is older. So what happens the PDW
picks up the ADO library all right automatically based on the Reference
setting in your project but it picks up the older version. If this
is the case then For this replace the Mdac_typ.exe in the
- C:\Program Files\Microsoft Visual Studio\VB98\Wizards\PDWizard\Redist
with the latest Mdac_typ.exe
-
- 'check this Goto Project|References from the vb menu. Look for a ActiveX
control that has MISSING next to it. If you see a missing that's the
problem. It can't find it. Sometimes it is a activeX version problem, you
may just need to pick a different version of the missing ActiveX control.
Ot you may need to somehow install the missing control or not use
it. As for where the debugger shows the problem, it's a red herring, just
look for the MISSING control in references.
To read:
How to make a web page available offline?
(CHECK) For users connecting in dial-up, once they
have viewed the page that contains the ActiveX control, they can have this page
saved offline, and work with it without having to connect each time. Just save
the URL to Favorites, right-click on this item in the Favorites, and set it
to offline. You can update it by clicking on Tools | Synchronize.
How to extract the CLSID from an OCX?
This routine uses Eduardo Morcillos' OleLib.Tlb
which must be added as a reference in the project). The OleLib.Tlb itself doesn't
need to be included in your setup.
- Private Function GetClsID(sFile$, sClass$) As String
- Dim i&, sName$, Obj As Object, pAttr&,
S As String * 64
- Dim TLI As ITypeLib, TI As ITypeInfo, TA As
TYPEATTR
-
- On Error Resume Next
-
- Set TLI = LoadTypeLibEx(sFile, REGKIND_NONE)
- If TLI Is Nothing Then Err.Clear: Exit Function
-
- GetClsID = Space(39)
- For i = 0 To TLI.GetTypeInfoCount - 1
- If TLI.GetTypeInfoType(i)
<> TKIND_COCLASS Then GoTo nxt
- Set TI = TLI.GetTypeInfo(i)
- TI.GetDocumentation
DISPID_UNKNOWN, sName, "", 0, ""
- If UCase(sName) <>
UCase(sClass) Then GoTo nxt
- pAttr = TI.GetTypeAttr
- MoveMemory TA, ByVal
pAttr, Len(TA)
- TI.ReleaseTypeAttr pAttr
- If TA.wTypeFlags Then
- StringFromGUID2
TA.iid, S, Len(S)
- GetClsID
= Left(S, InStr(S, Chr(0)) - 1)
- Exit
For
- End If
- nxt: Next i
- Err.Clear
- End Function
How to show an constituent form, wait for it to close, read how it went,
and act on this?
Since you can include forms in an ActiveX control, here's how to show a logon
form, wait for the user to select a push button OK/Cancel, read a property from
the form to know whether the password was correct, and enable a group of pushbuttons
on the ActiveX control itself:
Add this to the ActiveX control:
- Private Sub UserControl_Show()
- frmLogin.Show vbModal
- If frmLogin.ExitOK Then
- Dim iCounter As Integer
- For iCounter = 0 To
5
- Command1(iCounter).Enabled
= True
- Next iCounter
- Else
- MsgBox "Wrong password.
Hit F5 and try again", vbExclamation, "Wrong password"
- End If
- End Sub
Add a standard Logon form (Add form...), and add this code to the form:
- Private m_ExitOK As Boolean
-
- Private Sub cmdCancel_Click()
- m_blnSuccess = False
- Unload Me
- End Sub
-
- Private Sub cmdOK_Click()
- If txtPassword = "zorro" Then
- m_blnSuccess = True
- m_ExitOK = True
- Else
- m_blnSuccess = False
- m_ExitOK = False
- End If
- Unload Me
- End Sub
-
- Public Property Get ExitOK() As Variant
- ExitOK = m_ExitOK
- End Property
After accessing my control in a browser, I can no longer compile it
If you are using AvantBrowser, by default, it remains in memory (icon in
the taskbar) even if you closed its visible application window, and this includes
ActiveX controls that were loaded through a web page you visited. Use DLL Demon
to confirm that your control is still loaded, making it impossible for VB to
compile a new version ("Access denied"). Close AvantBrowser's icon
in the taskbar, and try again.
How to check that controls and other stuff is installed correctly?
Considering the number of changes made to a host to run an ActiveX control
(VB run-time, etc.), how could I check that things install properly, especially
on hosts connected to the Net via modem (hitting the ESC key or IE crashing
during the 3-4 minutes it takes to download the whole shebbang)? Can a VBScript
section do this?
Why is the CLSID different on the server and on the client host?
On the server, the web page contains CLASSID="CLSID:CE1A6A5A-4691-4977-8DCE-7192DA2CD80A".
Once I hit the page and accepted the ActiveX, it is located in the registry
under 8E2A8A55-F701-41EF-A529-BE296A9D8D41 :-)
Did I forget to hit F5 to refresh the Registry?
"Update ActiveX controls" in the Project Properties?
What does this option mean in General tab?
Can I add forms to a control?
Yes, but only modal forms are allowed (you'll get an error message when using
the control in IE anyway): Form1.Show vbModal .
How to register/unregister a bunch of ActiveX controls on a host?
for %f in (*.ocx *.dll) do regsvr32 /s "%f"
OR
for /r %i in (*.ocx) do regsvr32 /s "%i"
In Internet Explorer, why can't I set the default security environment to
"Internet" instead of "Local Intranet"?
Those are profiles used depending on the URL. Any local web site will be
handled based on the settings specified for the "Local Intranet" section;
Any Internet site will be handled by the settings in the ad hoc section. To
lower security settings for a given Internet web server, use the Trusted Sites
section.
How do I get rid of all the dialogs?
Note: For security reasons, you should lower security requirements only for
sites that you added in the Trusted Sites section.
Click on "Custom level...", set all items in the ActiveX section
to "Enable"; Scroll to the Scripting section, and set Active Scripting
to "Enable".)
Where is an ActiveX saved once it's been downloaded?
Unless otherwise specified in the INF file that is embedded in a CAB archive,
files are downloaded into C:\WINNT\Downloaded Program Files\
An ActiveX control fails installing with error 80040154 "Class not
registered"
Make sure that your INF file downloads VB binaries with the same version
that you used to build your ActiveX controls, ie. if your ActiveX control was
built with VB5, linking to VB6 stuff in your INF won't do you much good...
I want to know what changes are made to a host after downloading this ActiveX
stuff
On a brand new host...
- Install a utility to take a snapshot of the system (eg. InCtrl,
ConfigSafe, or Arkosoft
SystemSnapshot); MS' sysdiff utility stops dead when it encounters any
open file) before any change is made to
it
- Use your browser to connect to the web server, and
accept the VB fixed-cost stuff from Microsoft (ie. VB run-time, Automation,
etc.) and your ActiveX control(s). Make sure the whole thing works as planned
- Take a new snapshot, and check what changes have
been made
What tools other than VB can I use to build ActiveX controls?
PowerBasic with JazzAgeSoft's JA
COM/PB
- VC++
- Borland C++
- Delphi?
Can I run ActiveX controls in other browsers?
A plug-in is available for Netscape (and hence, should work also in Opera)
from NCompass
(bought
by Microsoft).
What is an OCA file?
An .OCA file is a binary file that functions as both an extended type library
file and a cache for the custom control file (What
Is an OCA file?)
You can delete oca files at will.. They'll be recreated on demand. If you
delete either oca's or tlb's, you should do the RegClean.. there are utilities
available for managing .tlb's.. there's at least one available at VB
Accelerator, RegClean
(ZDNet). Note that if you run RegClean a second time after applying its suggested
changes, it will often find additional entries that are no longer needed. I've
never had to do more than two, but it should eventually come up empty-handed
Two different version numbers to an OCX?
Note that there are two versions in an OCX, the version resource and the
typelib version. The version resource is what you see in windows, the typelib
version is what you'll see in the TypeLib key in the registry. You don't get
direct control over this second version number from the VBP.
However, you can use the 'PowerVB Binary
Compatibility Editor' add-in that comes with the CD Updates to "Advanced
Visual Basic 6" to accomplish this very easily. Of course, this
type of edit can have side effects, so you should be aware of why typelib versions
are incremented, along with being aware of all previously shipped versions of
the control, before making this type of modification.
Can I do without an OCX and hit the Win API instead?
In many cases (not all by any means), OCXs are merely wrappers for the functionality
that exists in Windows via the API. This is so that VB programmers not
familiar or comfortable with the API can still easily incorporate that functionality
in their programs. In the case of the Common Dialog control, if
you use the API functions GetOpenFileName, GetSaveFileName, etc., you aren't
using comdlg32.ocx, which means you don't need to distribute it either.
What's a property bag?
Can I register/unregister an ActiveX through a right-click in Windows Explorer?
Tip given here:
- REGEDIT4
-
- [HKEY_CLASSES_ROOT\.dll]
- "Content Type"="application/x-msdownload"
- @="dllfile"
-
- [HKEY_CLASSES_ROOT\dllfile]
- @="Application Extension"
-
- [HKEY_CLASSES_ROOT\dllfile\Shell\Register\command]
- @="regsvr32.exe \"%1\""
-
- [HKEY_CLASSES_ROOT\dllfile\Shell\UnRegister\command]
- @="regsvr32.exe /u \"%1\""
-
- [HKEY_CLASSES_ROOT\.ocx]
- @="ocxfile"
-
- [HKEY_CLASSES_ROOT\ocxfile]
- @="OCX"
-
- [HKEY_CLASSES_ROOT\ocxfile\Shell\Register\command]
- @="regsvr32.exe \"%1\""
-
- [HKEY_CLASSES_ROOT\ocxfile\Shell\UnRegister\command]
- @="regsvr32.exe /u \"%1\""
Registering an OCX through code
Your DLLs and OCXs have a built in DllRegisterServer function so you can
register them thru code as follows:
- Declare Function RegMyDll Lib "MyDll.dll" Alias "DllRegisterServer"()
as Long
- [...]
- Dim lResult as Long
- lResult = RegMyDll()
To find if an Active X is registered you must look up the Windows registry.
The easiest way is to search for a file name: MyOCX.DLL. If it is registred
the reference to it will be in the registry under HKEY_CLASSES_ROOT\TypeLib\{ITS
GUID} . This is non-trivial. Different types of DLLs register somewhat differently,
and the exact entries created are based in part on the OS version.
Loading an OCX through code
- Private Declare Function LoadLibrary Lib "kernel32" Alias
"LoadLibraryA" (ByVal _
- lpLibFileName As String) As Long
-
- Private Declare Function FreeLibrary Lib "kernel32" (ByVal
hLibModule As
- Long) As Long
-
- Private Sub Form_Click()
- If IsDLLAvailable("SHDOCVW.dll") Then
- MsgBox "OK"
- Else
- Beep
- ' MsgBox ApiErrorText(Err.LastDllError)
- ' for ApiErrorText, see:
- http://www.mvps.org/vb/index2.html?tips/formatmessage.htm
- End If
- End Sub
-
- Function IsDLLAvailable(ByVal DllFilename As String) As Boolean
- Dim hModule As Long
- ' attempt to load the module
- hModule = LoadLibrary(DllFilename)
- If hModule > 32 Then
- FreeLibrary hModule ' decrement
the DLL usage counter
- IsDLLAvailable = True
- End If
- End Function
Checking if an OCX is available
If you know the OCX's CLSID, you can use this code:
- Public Type CLSID '// This is the
same as a GUID
- Data1 As Long
- Data2 As Integer
- Data3 As Integer
- Data4(0 To 7) As Byte
- End Type
-
- '// Possible errors
- Public Const E_INVALIDARG As
Long = &H80070057
- Public Const E_UNEXPECTED As
Long = &H8000FFFF
- Public Const CO_E_CLASSSTRING As
Long = &H800401F3
- Public Const E_OUTOFMEMORY As
Long = &H8007000E
- Public Const REGDB_E_WRITEREGDB As
Long = &H80040151
-
- Public Declare Function CLSIDFromProgID Lib "OLE32" (ByVal
lpszProgID As String, pclsid As CLSID) As Long
-
- Public Function IsProgIDRegistered(ByVal strProgID As String) As Boolean
- '// a ProgID goes something like this: "MSComctlLib.Slider".
Passing a
- '// bogus value or a non-registered class will
return FALSE
- Dim pclsid As CLSID
- Dim hResult As Long
-
- On Error Resume Next
-
- hResult = CLSIDFromProgID(StrConv(strProgID,
vbUnicode), pclsid)
- IsProgIDRegistered = (hResult = 0)
- End Function
Instead of peeking in the Registry, we'll try to load the OCX, and catch
an error if it's not available:
- Function TestReg (ByVal sProgID As String) As Boolean
- On Error GoTo Trap
- Dim oMyObject As Object
- Set oMyObject = CreateObject(sProgID)
- TestReg = True
- Trap:
- End Function
Alternatives to ActiveX
Some alternatives for richer web clients :
TO-DO
- Download all VB stuff on our site, with MS sites as primary, and our
site as secondary d'load server
- Find what features in VB are not available when running the app as an
ActiveX control in a web page (no menu bar, only one form, etc.)
Issues
- How to name the ActiveX with a better ProgID than Project1.UserControl1?
Change both the project name and the control name. Actually, you really
must do this because using default names probably erases references to a
previous version (CHECK if VB doesn't just increase the number following
the control's name)
- IE 6 crashes every so often when loading an OCX (either via a CAB or
directly): Need to upgrade the VBScript engine?
- How does versioning work? The OBJECT and the INF use 4 digits, VB uses
3, and the Registry only two
- When packaging OCX's via a CAB, can I just increment the CAB's version
number to force update? Yes. Make sure you update the version number in
both the INF and the HTML page
- Versioning does not work reliably: Sometimes, even through the control
has changed on the server, the control is not updated on the client host
- In the OBJECT section, possible to use the control's ProgID instead
of its CLSID?
- In case versioning doesn't work reliably, is there a way to unregister
a control through VBS to force updating?
Although IE doesn't display any error, I can't delete a key in the Registry:
- <script language="vbscript">
- Dim oShell
- Set oShell = CreateObject("Wscript.shell")
- oShell.RegDelete "HKEY_CLASSES_ROOT\CLSID\{67A2A38D-3CA7-479A-9928-C4E070A691EE}"
- </script>
I think you need to install the WSH tool to access this object.
Temp stuff
Apparently, it is possible to use a control's ProgID instead of its CLSID
("[...] You need to specify the ProgID in the page to instantiate a control.
The ProgID or CLSID of a control may be retrieved manually from the system registry."
here)
Dim obExcelApp as Object
Set obExcelApp = CreateObject("Excel.Application")
HOW
TO: Use Licensed ActiveX Controls in Internet Explorer
Here's some VB code (how to access the registry in VBScript?) to check that
a control was correctly installed:
- Of course, you'd have to create the control, but you can use a usercontrol
to check the registry:
-
- Const HKEY_CLASSES_ROOT = &H80000000
-
- Private Declare Function RegOpenKey Lib "advapi32.dll" Alias
"RegOpenKeyA" (ByVal hKey As Long, ByVal lpSubKey As String, phkResult
As Long) As Long
-
- Private Declare Function GetSystemDirectory Lib "kernel32"
Alias "GetSystemDirectoryA" (ByVal lpBuffer As String, ByVal nSize
As Long) As Long
-
- Dim MySource As String
- Dim MyDest As String
- Const OF_CREATE = &H1000
- Const OF_READ = &H0
- Const OFS_MAXPATHNAME = 128
-
- Private Type OFSTRUCT
- cBytes As Byte
- fFixedDisk As Byte
- nErrCode As Integer
- Reserved1 As Integer
- Reserved2 As Integer
- szPathName(OFS_MAXPATHNAME)
As Byte
- End Type
-
- Private Declare Sub LZClose Lib "lz32.dll" (ByVal hfFile As
Long)
-
- Private Declare Function LZCopy Lib "lz32.dll" (ByVal hfSource
As Long, ByVal hfDest As Long) As Long
-
- Private Declare Function LZOpenFile Lib "lz32.dll" Alias "LZOpenFileA"
(ByVal lpszFile As String, lpOf As OFSTRUCT, ByVal style As Long) As Long
-
- Private Sub UserControl_Initialize()
- Dim iret as long
- Dim lHandle as Long
-
- iret = RegOpenKey(HKEY_CLASSES_ROOT,
"MSWinsock.Winsock", lHandle)
-
- If lHandle = 0 Then
- UserControl.AsyncRead
HTTP://www.yoursite.com/MSWinsock.ocx,vbasyncreadtypeFile
- End If
-
- 'Sub inside a sub???
-
- Private Sub Timer1_Timer()
- Static
C
- C
= C + 1
- If
C > 1 Then
- Timer1.Interval
= 0
-
Dim hsource As Long
-
Dim hdest As Long
-
Dim iret As Long
-
Dim OpenStruct As OFSTRUCT
-
Dim sBuffer as String * 255
-
Dim lbuffer as Long
-
Dim Pos as long
-
Dim iret1 as long
-
-
LBuffer = Len(sBuffer)
-
Iret1=GetSystemDirectory(sBuffer, lBuffer)
-
Pos = instr(sBuffer, CHR$(0))
-
MyDest = Left$(sBuffer, pos-1)
-
MyDest = MyDest & "\MSWinsock.ocx"
-
hsource = LZOpenFile(MySource, OpenStruct, OF_READ)
-
hdest = LZOpenFile(MyDest, OpenStruct, OF_CREATE)
-
iret = LZCopy(hsource, hdest)
-
If iret = -1 Then
-
MsgBox "File transfer failed"
-
Else
-
MsgBox "Transfer successful. " & Format$(iret,
"###,###,###,###") & "bytes were transfered."
-
End If
-
LZClose hdest
-
LZClose hsource
- End
If
-
- Dim
X
- X=Shell("Regsvr32
" & MyDest, vbhide)
- End Sub
-
- Private Sub UserControl_AsyncReadComplete(AsyncProp
As AsyncProperty)
- MySource
= AsyncProp.Value
- Timer1.Interval
= 1000
- End Sub
-
- End Sub
-
Private Sub UserControl_Show()
If Ambient.UserMode = True Then
MsgBox "Run-time"
Else
MsgBox "Design Time"
End If
End Sub
Private Sub UserControl_Initialize()
With UserControl
.picBOX.Move 0, 0, .ScaleWidth, .ScaleHeight
End With
End Sub
Private m_privateResize As Boolean
Event Click()
Event DblClick()
Event MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
Event MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Event MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
Event Resize()
Private Sub picBOX_Click()
RaiseEvent Click
End Sub
Public Property Let BackColor(ByVal New_BackColor As OLE_COLOR)
picBOX.BackColor() = New_BackColor
PropertyChanged "BackColor"
End Property
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
picBOX.Appearance = PropBag.ReadProperty("Appearance",
1)
Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
Call PropBag.WriteProperty("Appearance",
picBOX.Appearance, 1)
Once again, the property bag is what remembers what you set in the property
window when you design a form and place controls on it. If you do not
use the property bag, no matter what you set on the property window later will
never be saved.
Resources
Tools
Books
Sites
Documentation
- MSDN
DLL Help Database
- Building
Internet Applications
- Creating
an ActiveX Control
- Microsoft ActiveX Controls Overview
- Microsoft
Visual Basic Control Creation Edition 5.0
- Signing and Marking ActiveX Controls
- ActiveX Controls
- ActiveX Demystified
- ActiveX
Controls (MSDN Library)
- MS' Internet Explorer Components
Gallery
- MS
Internet Component Download
- Microsoft® Visual Basic® Scripting Edition VBScript
Tutorial
- Microsoft site, ActiveX
section
- Using
VBScript in HTML
- Webreference
- ActiveX, and a list
of controls
- Security
Tradeoffs: Java vs. ActiveX
- JavaScript,
Say Hello to ActiveX
- Active-X
- MS Front Page - Chapter
24 : ActiveX and VBScript
- Interacting
with ActiveX By Erin M. Carroll
- Visual Basic for Applications Unleashed Chapter
21—Web Page Programming: ActiveX and VBScript
- Introduction to Visual
Basic Scripting (VBScript)
- (French) Apprendre le
VBScript
- VBScript
and ActiveX
- Mastering VBScript
A free course of study at Free-Ed.Net
- ActiveX
Basics
- VBScripting
Solutions
- Usenet:
microsoft.public.vb.controls.*
- Protect Your Application
by Monte Hansen
- ActiveLock (software license)
- Generate/Validate
License Keys Based on User Name
- ActiveX: Security Issues
by Eric J. Grossman PH.D
- ActiveX Control Tutorial - Part 1
(Introduction to ActiveX controls), 2
(Properties, Enumeration, Resizing), 3
(Events, Mapping, ActiveX Wizard), 4
(Wizardy Whatnots Explained and Property), 5
(Packaging and deploying) by Karl Moore
- Late
Night ActiveX by Eric Tall and Mark Ginsburg
- ActiveX
Programming Unleashed
- ActiveX Programming with Visual C++ (Chapter 16 - Advanced
Topics on security)
- ActiveX
and VBScript by Paul Lomax and Rogers Cadenhead
- Presenting
ActiveX
- Teach
Yourself ActiveX in 21 Days
- Teach
Yourself VBScript in 21 Days by Keith Brophy, Timothy Koets
- Internet
Explorer Plug-In and ActiveX Companion
- INFO: Why CONFLICT Directories Are Created During Code Download
- INFO: CAB Files Distributed with Visual Basic 6.0
- HOWTO: Find More Information About Why Code Download Failed
- INFO: Internet Component Download Online Troubleshooter Is Available
- How to Stop an ActiveX
Control from Running in Internet Explorer
- HOWTO:
Download a Text File Using Internet Explorer Component Download
- ActiveX Component Download,
Web Deployment
- Using
INF Files
- INF
SourceDisksFiles Section
- Creating
an INF File
- Tools
for INF Files
- Sample chapter from Programming Visual Basic 6.0
- Buy controls from Active-X.com
- Determine
whether a file is in the Internet Explorer cache
- System
Internet Connection - Determining How and If Connected
- How to build an ActiveX Control Step by Step
- Visual
Basic runtime DLLs and Controls - When and how to install VB runtime DLLs,
the OLE DLLs and the Common Controls and Common Dialogs
- The
Makings Of An OCX Container
- VB
COM: VB6 Programmer’s Introduction to COM
- ActiveX -
my experience by brianhook
- COM in plain
C By Jeff Glatt
Forums
TEMP
This'll give you the clsid of the tlb that belongs to an
ocx (or dll) but keep in mind that an ocx can contain several controls that
each have their own clsid. Here's a startthough. Set a reference to 'TypeLib
Information' (tlbinf32), drop a command button on the form and run this.
- '=============
- Option Explicit
-
- Private Sub Command1_Click()
- MsgBox GetCLSIDFromFile _
- ("C:\WINNT\system32\MSCOMCTL.OCX")
- End Sub
-
- Private Function GetCLSIDFromFile _
- (ByVal FullPathToFile As String)
As String
-
- On Error GoTo ErrorTrap
- Dim oTLB As TLI.TypeLibInfo
- Dim iCount As Integer
-
- Set oTLB = TLI.TypeLibInfoFromFile(FullPathToFile)
-
- If oTLB Is Nothing Then
- MsgBox "No
TypeLib info found."
- Else
- GetCLSIDFromFile
= oTLB.Guid
- End If
-
- Terminate:
- Exit Function
-
- ErrorTrap:
- If Err.Number = &H80040202 Then
'can't get tlb info
- MsgBox "Failed
to get type lib info for file: [" _
- & FullPathToFile
& "[" & vbCrLf & vbCrLf _
- & Err.Description,
vbExclamation
- Else
- MsgBox "Error
" & Err.Number _
- &
vbCrLf & Err.Description, "GetCLSIDFromFile"
- End If
- Debug.Assert False
- Resume Terminate
- End Function
- '=============
For a complete example of how to extract just about anything
from an ocx, see: ActiveX Documenter http://vbaccelerator.com/home/VB/Utilities/ActiveX_Documenter/article.asp
It's a free utility (includes source) that will show all methods/properties/etc
in an activex component. Very handy tool.