DRAFT
January 1996
Microsoft Corporation
Download Microsoft Word (.DOC) format of this document (zipped, 28.6K).
Overview
Executive Summary
Introduction
Packaging Component Code for Automatic Download
The Internet Component Download Interface
Storing/Caching Downloaded Code
Future Directions
Needs That Aren't Met by Internet Component Download
Appendix--Registry Details
This document provides a description of the mechanism for downloading and installing code for ActiveX objects (components) using the Microsoft® ActiveX technologies. This mechanism is used internally by the Microsoft Internet Explorer for downloading ActiveX controls inserted into HTML pages.
Internet Component Download is a system service for downloading, certificate checking, and installing ActiveX component code from the Internet. This service is used by applications (such as Web browsers) to automatically download and install ActiveX objects from code repositories on the Internet. This document explains how code authors should prepare their components for automatic download. It then describes the interface for the component download mechanism, and finally provides some additional implementation details.
Internet Component Download is used within Microsoft Internet Explorer to automatically download ActiveX controls inserted into HTML pages using the <OBJECT> element in HTML. (In future releases, code for Document Object components will likewise be downloaded and installed automatically.) The mechanism for downloading components is exposed in an API that may be used in various other ActiveX containers. ActiveX control developers should follow the guidelines outlined below to package their controls so that they can be downloaded automatically by any container that uses the Internet Component Download mechanism.
Independent software vendors (ISVs) and authors of ActiveX objects for the Internet should package their implementations so that they may be downloaded automatically by Web browsers such as the Microsoft Internet Explorer. Such objects will be downloaded, for instance, when parsing the OBJECT tag in HTML. (The <OBJECT> tag used to be called the <INSERT> tag. This change was decided on by the World Wide Web Consortium [W3C] on 2/13.) For details, see the OBJECT tag specification. (See the ActiveX Development Kit, included in preliminary form on this Web site.)
The CODE attribute in an OBJECT tag contains a uniform resource locator (URL) pointing to the implementation of a given ActiveX object. This URL is of critical importance for component download, because it must specify all files necessary to implement a particular ActiveX object. HTML authors can author CODE URL to point to one of three file types. Component developers should choose one of the packaging schemes below for their ActiveX objects:
Besides the actual address of code, the CODE URL may also include an optional version number using the following syntax:
CODE=http://www.foo.com/bar.ocx#Version=a,b,c,d
The Internet Component Download mechanism will download and install the file only if the specified version number is more recent than any existing version of the same file currently installed in the system (see the Appendix for more information). If a version number is not specified with a file, it is assumed that any version installed on the system is recent enough.
When code to be downloaded is on an HTTP server, the HTTP header MIME request type may be used to specify which platform the code is to run on, thus allowing platform independence of the CODE URL.
The following multipurpose Internet mail extensions (MIME) types will be used to describe PEs (portable executables such as an .EXE, .DLL, or .OCX), cabinet files (.CAB), and setup scripts (.INF):
File description | MIME Type |
PE (portable executable) - .EXE, .DLL, .OCX | application/x-pe_%opersys%_%cpu% |
Cabinet files - .CAB | application/x-cabinet_%opersys%_%cpu% |
Setup scripts - .INF (platform independent) | application/x-setupscript |
%opersys% and %cpu% above will specify the operating system and CPU for the desired platform on which the downloaded components will be executed. For example, the MIME type for a Win32® cabinet file running on an Intel® x86-architecture processor would be application/x-cabinet_win32_x86.
The following are valid values for %opersys% and %cpu%:
Valid values for %opersys% | Meaning |
win32 | 32-bit Windows® operating systems (Windows 95 or Windows NT) |
mac | Macintosh® operating system |
<other> | Will be defined as necessary |
Valid values for %cpu% | Meaning |
x86 | Intel® x86 family of processors |
ppc | Motorola® PowerPC architecture |
mips | MIPS® architecture processors |
alpha | DEC® Alpha architecture |
When the code is on a non-HTTP server (for example, at a local LAN location), an .INF file can be used to achieve platform independence by specifying different URLs for files to be downloaded for different platforms. (See the section below on platform independence in .INF files.)
The .CAB format used for Internet Component Download is a non-proprietary format based on Lempel-Ziv compression. The Microsoft Internet SDK includes a free tool called DIANTZ.EXE that will package cabinet files into this non-proprietary format. There no specification of this .CAB format publicly available, although such a specification will be distributed as soon as possible.
The DIANTZ.EXE tool uses a .DDF "directive file" that specifies which files to combine into a cabinet. The syntax for using this tool from a command line is:
DIANTZ.EXE /f <directive file.ddf>
The example directive file below, CIRC3Z.DDF, would be used for creating a cabinet file containing two files: CIRC3.INF and CIRC3.OCX. It should be a straightforward process to add to this list of files.
; DIAMOND directive file for CIRC3.OCX+CIRC3.INF .OPTION EXPLICIT ; Generate errors on variable typos .Set CabinetNameTemplate=CIRC3Z.CAB ;** The files specified below are stored, compressed, in cabinet files .Set Cabinet=on .Set Compress=on circ3.INF circ3.OCX
Here is a sample .INF file that demonstrates the syntax understood by the Internet Component Download service. Only the .INF syntax below may be used to write setup scripts for Internet Component Download.
;Sample INF file for CIRC3.OCX [Add.Code] circ3.ocx=circ3.ocx random.dll=random.dll mfc40.dll=mfc40.dll foo.ocx=foo.ocx [circ3.ocx] ; lines below specify that the specified circ3.ocx (clsid, version) needs to be installed on ; the system. If doesn't exist already, can be downloaded from the given location (a .CAB) file=http://www.code.com/circ3/circ3.cab clsid={9DBAFCCF-592F-101B-85CE-00608CEC297B} FileVersion=1,0,0,143 [random.dll] ; lines below specify that the random.dll needs to be installed in the system ; if this doesn't exist already, it can be downloaded from the given location. file=http:// www.code.com/circ3/random.dll FileVersion= DestDir=10 ; DestDir can be set to 10 or 11 ( LDID_WIN or LDID_SYS by INF convention) ; this places files in \windows or \windows\system, respectively ; if no dest dir specified (typical case), code is installed in the fixed occache directory. [mfc40.dll] ; leaving the file location empty specifies that the installation ; needs mfc40 (version 4,0,0,5), but it should not be downloaded. ; if this file is not already present on the client machine, component download fails file= FileVersion=4,0,0,5 [foo.ocx] ; leaving the file location empty specifies that the installation ; needs the specified foo.ocx (clsid, version), but it should not be downloaded. ; if this file is not already present on the client machine, component download fails file= clsid={DEADBEEF-592F-101B-85CE-00608CEC297B} FileVersion=1,0,0,143
It is possible to create platform-independent setup scripts that pull files from different locations depending on the desired platform. Internet Component Download .INF files will use a scheme similar to the one described above under Platform independence and HTTP. Specifically, a sample platform-independent .INF file would include a text such as the following:
[circ3.ocx] ; lines below specify that the specified circ3.ocx (clsid, version) needs to be installed on ; the system. If doesn't exist already, can be downloaded from the given location (a .CAB) file_win32_x86=file://products/release/circ3/x86/circ3.cab file_win32_mips=file://products/release/circ3/mips/circ3.cab file_mac_ppc=file://products/release/circ3/macppc/circ3.cab clsid={9DBAFCCF-592F-101B-85CE-00608CEC297B} FileVersion=1,0,0,143
Thus the file= syntax used in the .INF file is expanded to file_%opersys%_%cpu =, allowing the .INF file to specify multiple locations where various platform-dependent modules can be found and downloaded. See the section above for valid values for %opersys% and %cpu%.
The Internet Component Download service is exposed via a single function, CoGetClassObjectFromURL(). This system function is called by an application that wishes to download, verify, and install code for an ActiveX component. The function is used in the implementation of Microsoft® Internet Explorer. The implementation uses URL monikers to asynchronously download code, and it uses the WinVerifyTrust service to verify validity of the code.
Related Documents:
The diagram below shows the implementation architecture for the Internet Component Download mechanism and its relation to other system services:
This section describes technical details of the Internet Component Download API used by applications (such as Web browsers) to download and install ActiveX object code.
STDAPI CoGetClassObjectFromURL ( [in] REFCLSID rclsid, [in] LPCWSTR szCodeURL, [in] DWORD dwFileVersionMS, [in] DWORD dwFileVersionLS, [in] LPCWSTR szContentTYPE, [in] LPBINDCTX pBindCtx, [in] DWORD dwClsContext, [in] LPVOID pvReserved, [in] REFIID riid, [out] VOID **ppv );
This function will return a factory object for a given rclsid. If no CLSID is specified (CLSID_NULL), this function will choose the appropriate CLSID for interpreting the Internet MIME type specified in szContentType. If the desired object is installed on the system, it is instantiated. Otherwise, the necessary code is downloaded and installed from the location specified in szCodeURL.
This "download and install" process involves the following steps:
Argument | Type | Description |
rclsid | REFCLSID | CLSID of the ActiveX object that needs to be installed. If value is CLSID_NULL, then szContentType is used to determine the CLSID. |
szCodeURL | LPCWSTR | URL pointing to the code for the ActiveX object. This may point to an executable, to an .INF file, or to a .CAB file (see below for details). |
dwFileVersionMS | DWORD | Major version number for the object that needs to be installed. |
dwFileVersionLS | DWORD | Minor version number for the object that needs to be installed. |
szContentType | LPCWSTR | MIME type that needs to be understood by the installed ActiveX object. If rclsid is CLSID_NULL, this string is used to determine the CLSID of the object that must be installed. |
pBindCtx | LPBINDCTX | A bind context to use for downloading/installing component code. The client should register its IBindStatusCallback in this bind context to receive callbacks during the download and installation process. (See the Asynchronous Monikers specification for details: It's included in the ActiveX Development Kit, available in preliminary form on this Web site. ) |
dwClsContext | DWORD | Values taken from the CLSCTX enumeration specifying the execution context for the class object. |
pvReserved | LPVOID | Reserved value, must be set to NULL. |
riid | REFIID | The interface to obtain on the factory object (typically IClassFactory). |
ppv | VOID ** | Pointer in which to store the interface pointer upon return if the call is synchronous. |
Returns | S_OK | Success. The ppv contains the requested interface pointer. |
E_PENDING | Component code will be downloaded and installed asynchronously. The client will receive notifications through the IBIndStatusCallback interface it has registered on pBindCtx. | |
E_NOINTERFACE | The desired interface pointer is not available. Other CoGetClassObject error return values are also possible here. |
In the common Web-browser scenario, the values for parameters passed to this function are read directly from an HTML OBJECT tag. For example, the szCodeURL, dwFileVersionMS, and dwFileVersionLS are specified inside an <OBJECT> tag as:
CODE=http://www.foo.com/bar.ocx#Version=a,b,c,d
where: szCodeURL is HTTP://WWW.FOO.COM/BAR.OCX, dwFileVersionMS is MAKEDWORD(A, B), and dwFileVersionLS is MAKEDWORD(C, D).
Because the downloading and installation of code occurs asynchronously, CoGetClassObjectFromURL will often return immediately with a return value of E_PENDING. At this point, the IBindStatusCallBack mechanism is used to communicate the status of the download operation to the client. (See the Asynchronous Monikers specification for details: It's included in the ActiveX Development Kit, available in preliminary form on this Web site. ) To participate in this communication, the client must implement IBindStatusCallback and register this interface in the pBindCtx passed into CoGetClassObjectFromURL using RegisterBindStatusCallback. The client can expect to be called with callback notifications for OnStartBinding (providing an IBinding for controlling the download), OnProgress (reporting progress), OnObjectAvailable (which returns the desired object interface pointer), and OnStopBinding (which returns error codes in case of an error). For further negotiations, the client must also implement ICodeInstall as described below.
The client of CoGetClassObjectFromURL will receive notification about the download/install process via the provided IBindStatusCallback interface. During the download process, the following additional values (from the BINDSTATUS enumeration) may be passed back as the
ulStatusCode parameter for IBindStatusCallback::OnProgress.
Value | Description |
BINDSTATUS_BEGINDOWNLOADCOMPONENTS | The download operation has begun downloading code for ActiveX components that will be installed before the object may be instantiated. The szStatusText accompanying IBindStatusCallback::OnProgress() provides the display name of the component being downloaded. |
BINDSTATUS_INSTALLINGCOMPONENTS | The download operation has downloaded code and is installing it. The szStatusText accompanying IBindStatusCallback::OnProgress() provides the display name of the component being installed. |
BINDSTATUS_ENDDOWNLOADCOMPONENTS | The download operation has finished downloading and installing all necessary code. The szStatusText accompanying OnProgress() provides the display name of the newly installed component. |
A code installation operation requires additional services from the client in order to complete the negotiation necessary for a download operation. Such services are requested using
IBindStatusCallback::QueryInterface. The specific interface requested in IBindStatusCallback::QueryInterface is ICodeInstall. This interface must be implemented by a client of Internet Component Download.
interface ICodeInstall : IUnknown { HRESULT NeedVerificationUI( [out] HWND* phwnd); HRESULT OnCodeInstallProblem( [in] ULONG ulStatusCode, [in] LPCWSTR szDestination, [in] LPCWSTR szSource, [in] DWORD dwReserved); };
ICodeInstall::NeedVerificationUI
This function is called when Internet Component Download needs to display a user interface (UI) message for verification of downloaded code. (Actually, this UI is displayed by the WinVerifyTrust mechanism that is used within Component Download.) When a client is called with this function, it has the opportunity to clear the message queue of its parent window before allowing a UI message to be displayed. If the client does not wish to display the UI message, code verification may continue, but components may fail to be installed.
Argument | Type | Description |
phwnd | HWND * | Client-provided HWND of the parent window for displaying code verification UI. If this parameter is NULL, the desktop window is used. If the value is INVALID_HANDLE_VALUE, then no code verification UI will be displayed, and certain necessary components may not be installed. |
Returns | S_OK | Success. |
E_INVALIDARG | The argument is invalid. |
ICodeInstall::OnCodeInstallProblem
This function is called when there is a problem with code installation. This notification gives the client a chance to resolve the problem, often by displaying a UI message, or by aborting the code installation process. If the client does not understand the problem, it should return E_ABORT by default to abort the code installation process, because returning S_OK would imply retrying the operation.
Argument | Type | Description |
ulStatusCode | ULONG | Status code describing what problem occurred. A member of CIP_STATUS. |
szDestination | LPCWSTR | The name of the existing file that was causing a problem. This may be the name of an existing file that needs to be overwritten, the name of a directory causing access problems, or the name of a drive that is full. |
szSource | LPCWSTR | Name of the new file to replace the existing file (if applicable). |
dwReserved | DWORD | Reserved for future use. |
Returns | S_OK | Continue the installation process. If there was an "access denied" or full-disk problem, retry the installation. If there was an existing file (newer or older version), overwrite it. |
S_FALSE | Skip this particular file, but continue with the rest of the code installation process. Note that this is the typical response for the CIP_NEWER_VERSION_EXISTS case. | |
E_ABORT | Abort the code installation process. | |
E_INVALIDARG | The given arguments are invalid. |
The ulStatusCode parameter above is one of the following values:
typedef enum { CIP_DISK_FULL, CIP_ACCESS_DENIED, CIP_OLDER_VERSION_EXISTS, CIP_NEWER_VERSION_EXISTS, CIP_NAME_CONFLICT, CIP_TRUST_VERIFICATION_COMPONENT_MISSING } CIP_STATUS;
Value | Description |
CIP_DRIVE_FULL | The drive specified in szDestination is full. |
CIP_ACCESS_DENIED | Access to the file specified in szDestination is denied. |
CIP_OLDER_VERSION_EXISTS | An existing file (older version) specified in szDestination needs to be overwritten by the file specified in szSource. |
CIP_NEWER_VERSION_EXISTS | A file exists (specified in szDestination) that is a newer version of a file to be installed (specified in szSource). |
CIP_NAME_CONFLICT | A file exists (specified in szDestination) that has a naming conflict with a file to be installed (specified in szSource). The existing file is neither a newer nor an older version of the new filebethey are mismatched but have the same filename. |
CIP_TRUST_VERIFICATION_COMPONENT_MISSING | The code installation process cannot find the necessary component (WinVerifyTrust) for verifying trust in downloaded code. szSource specifies the name of the file that cannot be certified. The client should display a UI message asking the user whether or not to install the untrusted code, and should then return E_ABORT to abort the download, S_OK to continue anyway, or S_FALSE to skip this file but continue (usually dangerous). |
The Code Download installs most new code in a permanent store in windows\system\occache. (This directory location is hard-coded for initial releases. In future releases users may use a registry setting or a Control Panel applet to choose this directory. Component code will be installed in this directory unless a previous version exist. In such cases, the Component Download mechanism will attempt to replace the previous version and invoke ICodeInstall::OnCodeInstallProblem.) Some components (helper DLLs that need to be on the system path but currently are not) will also be installed in \windows and \windows\system. All downloaded code is registered using a new Registry "Module Usage" section that keeps track of such code. Downloaded code is not removed automatically, but it is possible in the future to add a UI message to the Control Panel (or elsewhere) allowing a user to clean up this directory.
For future releases, it is also possible to convert this "permanent store" into a code cache that retains only popular downloaded code and deletes old unused code automatically. This migration plan justifies use of a permanent store for the first version. See the Appendix for information on how downloaded code is listed in the Registry and how a code cache could function in future releases.
The Internet Component Download service will provide for an Internet "search path" stored in the Registry. This path is a list of Web servers that will be queried every time components are downloaded using CoGetClassObjectFromURL. This way, even if an <OBJECT> tag in an HTML document does not specify a location to download code for an embedded ActiveX control, the Internet Component Download will still use the Internet "search path" to find the necessary component.
Further specification of the Internet search path is still under development.
Although Internet Component Download currently supports a limited .INF setup-script syntax, future releases will take into consideration the need to support "hooks" that allow custom setup handlers to interact with the component download and installation process. No further details are available at this time.
There are situations in which code needs to be downloaded with trust verification but the code is not an ActiveX object. Such cases are not addressed by the current specification of the Internet Component Download mechanism. Solutions for these cases need to use the WinVerifyTrust mechanism directly, as detailed below:
The Internet Component Download service will keep Registry entries for every new downloaded component. These Registry entries will be useful for writing a utility for cleaning up the code storage, or migrating the Internet Component Download service to use a code cache rather than a permanent store. (Either of these would be intelligent about uninstalling and de-registering component code using its existing self-registration mechanism.)
To do correct code caching, the existing SharedDLL reference counting scheme will not suffice, because reference counts are easily inflated. Specifically, any application that is reinstalled increases the reference count on a shared DLL even though that DLL already has a reference count belonging to the particular application. (This is already broken for current reference counting, but it will most certainly fail for the Code Download, in which OCXes are used by multiple pages quite regularly, and there is no way of knowing which OCXes need reference counts.
To do reference counting correctly, Internet Component Download will maintain a
ModuleUsage section in the Registry that holds a list of "owners" and "clients" for each shared module. Thus the Registry can keep track of who is using a shared module, not just how many clients that module has. The Registry entries would use the following syntax:
[ModuleUsage] [Fully Qualified Path&File Name] FileVersion=a,b,c,d Owner = Friendly Name/ID of Owner [Clients] ID of Client1 = <peculiar to this client>
A ModuleUsage section in a sample Registry would look something like the following:
Under My Computer\HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion: [ModuleUsage] [c:\windows/system/mfc40.dll] FileVersion=0,4,0,0 Owner = MSCodeDownloaderID [Clients} MSCodeDownloaderID= <any info, or default> AnotherAppID= <any info, or default>
Key name | Description |
Fully Qualified Path&Filename | This is the full path of the shared module. This name has to use "/"s instead of "\"s because the "\" is an invalid character in a key name. |
Owner | The application that installs the shared module and creates the original ModuleUsage section will put an identifier in the owner key section. If the DLL already existed on the system and this Module Usage key did not exist, the owner key should be set to "Unknown" and the DLL should not be removed on uninstallation. The owner should also enlist itself as a client. |
File Version | The version number for the shared module. |
Clients | IDs of various clients who are using the shared module. |
Every client of this module is expected to increment and decrement the existing SharedDLL section in the Registry as well (a client only increments this value once when it adds itself as a client under ModuleUsage). This allows a migration path for apps currently implementing onlya SharedDLL scheme.
This Registry information complements the reference counts in the SharedDLL section by tracking which clients are actually using a shared module. This counting scheme will work correctly and allow caching of downloaded code. Furthermore, when downloading files, Internet Component Download can use this Registry information as an efficient shortcut for verifying whether a file needs to be overwritten because it is an out-of-date version.
Return to the Code Signing home page
© 1996 Microsoft Corporation