Hardware and software setup

Error Cannot create object by activex container. Creating ActiveX Control Containers

Alexander Kostarev
R-Style Software Lab technology department programmer.

Creating ActiveX controls is widely covered in the specialized literature. However, it discusses techniques for writing ActiveX containers much less frequently, mostly only as part of their interaction with ActiveX objects. Even fewer publications are devoted to the procedures for developing containers that support their own programming interface (API), which allows working with them and the objects they contain from other applications or scripting languages. Examples of such containers are such software products as Microsoft Visual Basic, Borland Delphi, etc.

Nevertheless, a number of tasks cannot be solved on the basis of existing containers - this requires specialized containers of controls. One such challenge is to create an extensible application that allows you to automate common operations that could not have been foreseen during development. Automation requires that the application expose its objects externally and be integrated with the extension development tool. Building user interface is based in most cases on the insertion of various controls into the form - a container of ActiveX objects. Thus the creation tool requires the creation of an ActiveX container.

We will consider some issues that arise when introducing a component architecture into a tool complex, as well as methods for solving them. This may be of interest to developers of both control containers and developers of ActiveX objects themselves, as this article demonstrates the purpose and use of the various methods of the standard control interfaces on the container side.

The proposed solutions are based on the experience of developing the RS-Forms tool complex - a new software product R-Style Software Lab. RS-Forms includes a development tool GUI user on Windows platform, an execution environment for programs created using the RSL*, C and C++ languages, as well as a debugging system for RSL programs.

*Object RSL - programming language high level, created by R-Style Software Lab. See http://www.softlab.ru/products/rsl/ for details. - Note. ed.

As part of the project, the first version of the form designer was implemented (Fig. 1), which allows you to create forms, embed both standard controls and arbitrary ActiveX objects in them, save ready-made forms in storage on a permanent storage medium and load them from it. With the help of the designer, you can view the properties, methods and events of any control element embedded in the form, change the property values.

The designer is based on an ActiveX control container (form) that provides the functionality described above. In addition, the form supports various options settings for its presentation, including the percentage binding of embedded elements to the borders, control of the sequence of their bypass by the keyboard, their visibility, typeface and font size, background color, text, etc.

In addition to developing a graphical user interface, the designer has a mechanism for automatically generating code in C++ and RSL. It is important to note that all operations performed on the form in the designer are also available in runtime mode from the program code.

Rice. 1. Form designer.

Created in the designer graphic forms can be used in any C/C++ application, as well as from any scripting language such as Visual Basic or RSL. When using forms in C++ applications developed with the MFC library, the designer can be used as a dialog resource editor.

Now let's discuss the concept of building a container and the principles of working with ActiveX controls.

Basic Container Functions

Any container of controls should have functionality that would allow you to create ActiveX objects, ensure their correct operation, remove them from random access memory, as well as store items in the object store on a permanent storage medium and load them from it*. The container includes a number of components (Fig. 2) that provide standard (according to Microsoft ActiveX technology) functionality necessary for the controls to work correctly.

* General issues of building containers and servers of COM objects are discussed in the book by D. Chappel "ActiveX and OLE Technologies" - M .: "Russian Edition", 1997.

The container maintains a collection (for example, a list) of connection objects with ActiveX controls, one connection object per control. In addition, a programmable container must provide a standard mechanism for manipulating the elements of this collection.

The control site object is responsible for the correct interaction of the corresponding element with the container. Each connection object contains a subobject that extends the control with a container-specific set of properties, methods, and events. Such a sub-object is called an extended control. An example of extended properties is a name (Name), a location in a container (Width, Left), and so on. The specified sets are properties of the container, not of any individual control, although that is what it looks like to the user of the system. There are several options for implementing an extended control. For example, it can be a subobject of the communication object (see Figure 2) or a real COM object that aggregates the original control. Each of the options has its own advantages and disadvantages. In this article, we consider only the first method.

Each extended control contains as a subobject an event sink object from its associated control (Figure 2). Its tasks include the primary identification of received events (whether custom event processing is required or not) and, if necessary, passing them to its owner object (extended control), which provides event routing along the container object hierarchy.

Control Creation Script

Injecting a control into a container consists of three phases: creating an ActiveX object, initializing it, and activating it.

Controls are created in the container's address space using standard features COM like CoCreateInstance. The corresponding globally unique CLSID is passed to the function as the control's ID. It should be noted that the container must support various options for identifying COM objects in the system - such as the program identifier ProgID, a unique class identifier in the form of a string, etc.

The main purpose of the initialization phase is to pass a pointer to the IOleClientSite interface of the connection object to the control via the IOleObject::SetClientSite function and call the IPersistStreamInit::InitNew or IPersistStreamInit::Load function (depending on whether the object is being loaded from storage or not). Passing an object a pointer to the IOleClientSite interface can occur before loading/initialization or after; the moment of transmission is determined by the presence of the OLEMISC_SETCLIENTSITEFIRST (IOleObject::GetMiscStatus) attribute. This is significant, because the pointer passing determines at what point in time the control will receive the values ​​of the ambient properties from the container. If this feature is ignored, then the further functioning of the ActiveX object may be incorrect.

Then, within the framework of the considered phase, you need to carry out the initial initialization of the properties of the extended control that complements the created ActiveX object. For example, you need to correctly set the name of the object (initialize the Name property, which provides identification of controls within the container). Any control embedded in a programmable container must support this property, but it is still a property of the container. Often, by default, objects are given the short name of the class to which they belong (this name is returned by the IOleObject::GetUserType method for the USERCLASSTYPE_SHORT parameter), with a numeric index appended to ensure that the container control names are unique. If receive specified name fails, or if it does not satisfy the logic of the container, then some predefined name can be given with the appropriate index.

Activating a control implies a certain sequence of actions. The first step is to establish an ActiveX object backlink to the link object in the container (control site). To do this, the IOleObject::Advise method is called, which is passed a pointer to standard interface IAdviseSink connection object. Next, you need to correctly request the interface of the IViewObject family (according to the specification, an ActiveX object can support the IViewObject, IViewObject2, IViewObjectEx interfaces that are in the inheritance hierarchy) and establish a feedback for it by calling the IViewObject::SetAdvise method passing a pointer to IAdviseSink. In addition, you need to tell the control the name of its container (this is implemented by calling the IOleObject::SetHostName method), request and save all the interfaces required for correct work with the ActiveX object (at least IOleInPlaceObject and IOleControl). The last thing to do to render the control visually is to call the IOleObject::DoVerb* function with the OLEIVERB_INPLACEACTIVATE parameter.

*In ATL implementation specified function, among other things, is responsible for creating a window for normal (windowed) controls.

Control Deletion Script

To remove a control embedded in a container from memory, you need to exclude from the collection the object of association with the control corresponding to it, and then perform two operations in sequence: break feedback and freeing stored pointers to interfaces of the ActiveX object.

To break backlinks, you must first inform the element being removed about the need to release (by calling the IUnknown::Release method) the pointers it holds to the IAdviseSink interface of the link object. To do this, the IViewObject::SetAdvise methods are called (passing NULL as an argument) and IOleObject::Unadvise, which needs to be provided with the relationship identifier saved during the activation phase. Next, you need to activate the procedure for deinitializing the ActiveX object (by calling the IOleObject::Close function). The next step is to tell the control to free the IOleClientSite interface pointer by calling IOleObject::SetClientSite with a NULL parameter.

The phase of releasing stored pointers to control interfaces consists in calling the Release method on them one by one. As soon as the last pointer is freed, the object (in accordance with COM technology) will be removed from RAM.

Save and Load Script

Saving a container object to storage, regardless of the type of the latter, is about saving the properties of the container (such as environment properties) and the collection of embedded controls, i.e., the IDs and properties (including extended ones) of each object that belongs to the collection. The control's identifier can be the globally unique identifier of the CLSID class. This will allow the initialization stage to create the required ActiveX object and load it with the data contained in the store after the specified identifier. To save the properties of a control, for example, to a stream, the Save method of the standard ActiveX object interface IPersistStreamInit is called. To load, the Load method of the same interface is called.

This save procedure ensures that the container object is later restored from storage. The described method works well, provided that no version changes or removal of any controls from the system occurred between the time of saving and the time of loading. Such situations often arise when migrating a data store from one computer to another where the saved ActiveX controls have not been installed or registered. In this case, loading the container object from the storage will either lead to a fatal termination of the program, or cause an error loading the entire container as a whole. To prevent errors, it is necessary to clearly establish the boundary between the data of various controls by writing to the storage after the object identifier the size of the information stored by it. This will allow the load phase to accurately position itself at the beginning of each ActiveX object's data, as well as skip controls that are not registered in the system, but load the container object as a whole.

ActiveX Object Collection Interfaces

According to the standard, the control container must provide interaction between ActiveX objects embedded in it. To do this, you must support the IOleContainer interface, which allows you to enumerate all the controls inserted into it. If there is an extended control, the enumeration must traverse its IUnknown interfaces, not the interfaces of the underlying object.

To provide access to a collection to automation clients, use the standard object collection interface. The standard collection includes the Add, Remove, Clear, Item methods, and the _NewEnum and Count properties, which provide a comprehensive iteration of the elements. For example, the design language Visual Basic for each uses the _NewEnum property to enumerate elements, and the construction for next involves using the Count property and the Item method. In Object RSL, the _NewEnum property is used when accessing standard method CreateEnum ActiveX object. This is illustrated, for example, by an RSL program that prints the names of files opened in the application using the specified method. Microsoft Excel(its text is given below).

import rslx; ob = ActiveX("Excel.Application", null, true); en = ob.Workbooks.CreateEnum; while (en.next) println(en.item.Name) end;

The above scenarios allow you to develop functions for adding a control to a container and removing it from it. In most cases, the add function creates an association object with the control (which stores all the pointers to the interfaces of the ActiveX object that it needs to work) and calls a similar function on it. The latter, in turn, implements the implementation scenario described above (perhaps without the activation phase). If the formation of the ActiveX object in RAM was successful, then the container function adds the corresponding link object to the collection. Often, due to their similarity, the procedures for embedding and loading a control from the store are combined.

* * *

We have covered here the main issues related to building control containers: injection, visual display, saving and loading an ActiveX object, as well as its correct removal from RAM. However, in the process of creating a graphical working environment, we needed to implement several containers that would differ from each other in the provided automation interfaces, subsets of ActiveX objects that can be injected, sets of properties, methods and events of extended controls, and so on. For this, a model was proposed that allows you to create various container elements and integrates well with the ATL library. Independence from specific interfaces is achieved through the use of template classes, whose parameters are these interfaces.

*For example, the Tab control is a container for property pages, which are general purpose containers.

This model allows you to quickly create basic variants of various ActiveX objects that have "container logic" inherent in them. In addition, the implemented infrastructure allows you to create containers that are not controls. Such a container can be placed as Windows windows to any part of the application being developed and then, by sending appropriate messages, implement various controls into it.

The result is a fairly flexible architecture for building containers, with which you can create a Wizard (Wizard) that extends functionality Microsoft environments visual studio to the mechanism for generating the skeleton of the container.


Manually editing the Windows registry to remove invalid keys Error 800A01AD is not recommended unless you are PC service professional. Mistakes made while editing the registry can render your PC unusable and cause irreparable damage to your operating system. In fact, even a single comma in the wrong place can prevent your computer from booting up!

Because of this risk, we highly recommend using a trusted registry cleaner such as WinThruster [Download] (Developed by Microsoft Gold Certified Partner) to scan and repair any Error 800A01AD. By using the [Download] Registry Cleaner, you can automate the process of finding broken registry entries, missing file references (like the one causing your %%error_name%%) error, and broken links within the registry. Before each scan, an automatically created backup copy, which allows you to undo any changes with a single click and protects you from possible damage to your computer. The best part is that fixing [Download] registry errors can drastically improve system speed and performance.


A warning: Unless you are an advanced PC user, we do NOT recommend manually editing the Windows Registry. Incorrect use of the Registry Editor can lead to serious problems and require reinstalling Windows. We do not guarantee that problems resulting from misuse of Registry Editor can be resolved. You use the Registry Editor at your own risk.

Before manually restoring Windows registry, you need to create a backup by exporting the part of the registry associated with Error 800A01AD (for example, ActiveX):

  1. Click on the button Begin.
  2. Enter " command" in search bar... DO NOT PRESS YET ENTER!
  3. Holding keys CTRL-Shift on the keyboard, press ENTER.
  4. An access dialog will be displayed.
  5. Click Yes.
  6. The black box opens with a blinking cursor.
  7. Enter " regedit" and press ENTER.
  8. In the Registry Editor, select the Error 800A01AD-related key (eg. ActiveX) you want to back up.
  9. On the menu File select Export.
  10. Listed Save to select the folder where you want to save the backup copy of the ActiveX key.
  11. In field File name enter a name for the backup file, such as "ActiveX Backup".
  12. Make sure the field Export range value selected Selected branch.
  13. Click Save.
  14. The file will be saved with .reg extension.
  15. You now have a backup of your ActiveX-related registry entry.

The next steps for manually editing the registry will not be covered in this article, as they are likely to damage your system. If you would like more information on editing the registry manually, please see the links below.

Systems and were available all related . This error has the following causes and solutions:

    The class is not registered. For example, there is no mention of a class in the system registry, or the class is mentioned but points to a file of the wrong type, or to a file that cannot be found. If possible, start the object application. If the registry information is incorrect or out of date, the application will check the registry and correct the information. If running the application does not resolve the issue, rerun the application installer;

    Can't use DLL The required by the object because it was not found or was found to be corrupted. Make sure all related DLLs are available. For example, a Data Access Object (DAO) requires support for DLLs that vary by platform. If this is the cause of the error, you need to re-run the installer for that item;

    The object is available on the machine, but is licensed, and it can't check if the license required to instantiate the object is available.

    Some objects can only be instantiated after the component finds license key A that confirms that this object is registered for instantiation on this computer. If there is a reference to an object in a properly set or correct key is provided automatically.

    If the attempt to create an instance is the result of a function call CreateObject or GetObject, the object must find the key. In this case, it can search the system registry or search special file, which it creates during installation (for example, with a .LIC extension). If the key cannot be found, the object cannot be instantiated. If the end user misconfigured the object application, permanently deleted desired file or changed the system registry, the object will not be able to find its key. If the key cannot be found, the object cannot be instantiated. In this case, instantiation might work on the developer's system, but not on the user's system. The user must reinstall the licensed item;

    You are trying to use the get object function GetObject to get a reference to the class created with using Visual basic. GetObject cannot be used to get a reference to a class created with Visual Basic;

    Access to the object is explicitly denied. For example, you are trying to access a data object that is currently in use and locked to prevent a deadlock. In this case, you may be able to access the object at another time.

For getting additional information select the item you have a question about and press F1 (Windows) or HELP (Macintosh).

Liked the article? Share with friends!
Was this article helpful?
Yes
Not
Thanks for your feedback!
Something went wrong and your vote was not counted.
Thanks. Your message has been sent
Did you find an error in the text?
Select it, click Ctrl+Enter and we'll fix it!