Création de conteneurs de contrôle ActiveX. Création d'un script de création de contrôle de conteneurs de contrôle ActiveX

Les systèmes et tous ceux associés étaient disponibles. Cette erreur a les causes et solutions suivantes :

    Classe non enregistrée. Par exemple, il n'y a aucune mention d'une classe dans le registre système, ou la classe est mentionnée mais pointe vers un fichier du mauvais type ou vers un fichier introuvable. Si possible, démarrez l'application objet. Si les informations du registre sont incorrectes ou obsolètes, l'application vérifiera le registre et corrigera les informations. Si l'exécution de l'application ne résout pas le problème, exécutez à nouveau le programme d'installation de l'application ;

    Je ne peux pas utiliser DLL, requis par l'objet car il n'a pas été trouvé ou a été trouvé corrompu. Assurez-vous que toutes les DLL associées sont disponibles. Par exemple, un objet d'accès aux données (DAO) nécessite la prise en charge de DLL qui diffèrent selon la plateforme. Si telle est la cause de l'erreur, vous devrez réexécuter le programme d'installation pour cet élément ;

    L'objet est disponible sur l'ordinateur, mais il est sous licence et il ne parvient pas à vérifier la disponibilité de la licence requise pour instancier l'objet.

    Les instances de certains objets ne peuvent être créées qu'une fois que le composant a trouvé clé de licence, confirmant l'enregistrement de cet objet pour créer une instance sur cet ordinateur. S'il y a une référence à l'objet dans une clé correctement installée ou correcte, elle est fournie automatiquement.

    Si la tentative de création d'une instance est le résultat d'un appel de fonction Créer un objet ou ObtenirObjet, l'objet doit trouver la clé. Dans ce cas, il peut effectuer une recherche dans le registre système ou rechercher un fichier spécial qu'il crée lors de l'installation (par exemple, avec une extension .LIC). Si la clé est introuvable, l'instance d'objet ne peut pas être créée. Si l'utilisateur final a mal configuré l'objet application, supprimé définitivement fichier requis ou modifié le registre système, l'objet ne pourra pas trouver sa clé. Si la clé est introuvable, l'objet ne peut pas être instancié. Dans ce cas, l'instanciation peut fonctionner sur le système du développeur, mais pas sur celui de l'utilisateur. L'utilisateur doit réinstaller l'élément sous licence ;

    Vous essayez d'utiliser la fonction get object ObtenirObjet pour obtenir une référence à une classe créée à l’aide de Visual Basic. ObtenirObjet ne peut pas être utilisé pour obtenir une référence à une classe créée à l'aide de Visual Basic ;

    L'accès à l'objet est explicitement refusé. Par exemple, vous essayez d'accéder à un objet de données actuellement utilisé et verrouillé pour éviter un blocage. Dans ce cas, vous pourrez peut-être accéder à l'élément à un autre moment.

Pour plus d'informations, sélectionnez l'élément qui vous intéresse et appuyez sur F1 (Windows) ou AIDE (Macintosh).

Alexandre Kostarev
programmeur dans le département technologique du R-Style Software Lab.

La création de contrôles ActiveX est largement abordée dans la littérature spécialisée. Cependant, les méthodes d'écriture de conteneurs ActiveX sont abordées beaucoup moins fréquemment, principalement uniquement en termes d'interaction avec les objets ActiveX. Encore moins de publications sont consacrées aux procédures de développement de conteneurs prenant en charge leur propre interface de programmation (API), qui permet de travailler avec eux et les objets qu'ils contiennent à partir d'autres applications ou langages de script. Des exemples de tels conteneurs sont des produits logiciels tels que Microsoft Visual Basic, Borland Delphi, etc.

Cependant, il n'est pas possible de résoudre un certain nombre de problèmes avec les conteneurs existants ; cela nécessite des conteneurs de contrôle spécialisés. L'une de ces tâches consiste à créer une application extensible qui vous permet d'automatiser des opérations fréquentes qui n'auraient pas pu être prévues lors du développement. L'automatisation nécessite que l'application expose ses objets en externe et soit intégrée à un outil de développement d'extension. La construction de l'interface utilisateur repose dans la plupart des cas sur l'insertion de divers contrôles dans un formulaire - un conteneur d'objets ActiveX. Ainsi, créer un outil nécessite de créer un conteneur ActiveX.

Nous examinerons certains problèmes qui surviennent lors de l'introduction de l'architecture des composants dans une boîte à outils, ainsi que les méthodes pour les résoudre. Cela peut intéresser à la fois les développeurs de conteneurs de contrôle et les développeurs d'objets ActiveX eux-mêmes, puisque l'article démontre le but et l'utilisation de diverses méthodes interfaces standard pour les contrôles côté conteneur.

Les solutions proposées sont basées sur l'expérience du développement de la boîte à outils RS-Forms - un nouveau produit logiciel Société de laboratoire de logiciels R-Style. RS-Forms comprend un outil de développement Interface graphique utilisateur sur Plateforme Windows, un environnement d'exécution pour les programmes créés à l'aide des langages RSL*, C et C++, ainsi qu'un système de débogage des programmes RSL.

*Object RSL est un langage de programmation de haut niveau créé par R-Style Software Lab. Pour plus de détails, voir http://www.softlab.ru/products/rsl/. - Note éd.

Dans le cadre du projet, la première version du concepteur de formulaires a été implémentée (Fig. 1), qui vous permet de créer des formulaires, d'y implémenter à la fois des contrôles standard et des objets ActiveX arbitraires, d'enregistrer des formulaires prêts à l'emploi sur un stockage permanent. support et chargez-les à partir de celui-ci. À l'aide du concepteur, vous pouvez afficher les propriétés, les méthodes et les événements de tout élément de contrôle incorporé dans le formulaire et modifier les valeurs des propriétés.

Le concepteur est construit sur un conteneur de contrôle ActiveX (formulaire) qui fournit les fonctionnalités décrites ci-dessus. De plus, le formulaire prend en charge diverses options paramètres pour sa présentation, y compris le pourcentage de liaison des éléments incorporés aux bordures, le contrôle de la séquence de leur parcours par le clavier, leur visibilité, la police et la taille de la police, la couleur de fond, le texte, etc.

En plus de développer une interface utilisateur graphique, le concepteur inclut un mécanisme de génération automatique de code en C++ et RSL. Il est important de noter que toutes les opérations effectuées sur le formulaire dans le concepteur sont également disponibles en mode exécution à partir du code du programme.

Riz. 1. Concepteur de formulaires.

Les formulaires graphiques créés dans le concepteur peuvent être utilisés dans n'importe quelle application C/C++, ainsi qu'à partir de n'importe quel langage de script, tel que Visual Basic ou RSL. Lorsque vous utilisez des formulaires dans des applications C++ développées avec la bibliothèque MFC, vous pouvez utiliser le concepteur comme éditeur de ressources de dialogue.

Discutons maintenant du concept de création d'un conteneur et des principes d'utilisation des contrôles ActiveX.

Fonctions de base du conteneur

Tout conteneur de contrôles doit avoir une fonctionnalité qui vous permet de créer des objets ActiveX, de garantir leur bon fonctionnement et de les supprimer de mémoire vive, ainsi que de sauvegarder les éléments du stockage d'objets sur un support de stockage permanent et de les charger à partir de celui-ci*. Le conteneur comprend un certain nombre de composants (Fig. 2) qui fournissent les fonctionnalités standard (conformément à la technologie Microsoft ActiveX) nécessaires au bon fonctionnement des contrôles.

*Les problèmes généraux liés à la création de conteneurs et de serveurs d'objets COM sont abordés dans le livre de D. Chappel « ActiveX and OLE Technologies » - M. : « Russian Edition », 1997.

Le conteneur gère une collection (par exemple, une liste) d'objets de communication avec des contrôles ActiveX : un objet de communication par élément de contrôle. De plus, un conteneur programmable doit fournir un mécanisme standard pour manipuler les éléments de cette collection.

Le site de contrôle est responsable de la bonne interaction de l'élément correspondant avec le conteneur. Chaque objet de communication contient un sous-objet qui étend le contrôle avec des ensembles de propriétés, de méthodes et d'événements spécifiques au conteneur standard. Ce sous-objet est appelé contrôle étendu. Un exemple de propriétés étendues est le nom (Name), l'emplacement dans le conteneur (Width, Left), etc. Les ensembles spécifiés sont des propriétés du conteneur, et non d'un contrôle individuel, bien que ce soit exactement ce à quoi cela ressemble pour l'utilisateur du système. Il existe plusieurs options pour mettre en œuvre un contrôle étendu. Par exemple, il peut s'agir d'un sous-objet d'un objet de communication (voir Figure 2) ou d'un objet COM réel qui regroupe le contrôle d'origine. Chaque option a ses propres avantages et inconvénients. Dans cet article, nous considérons uniquement la première méthode.

Chaque contrôle étendu contient comme sous-objet un objet récepteur d'événements du contrôle qui lui est associé (Fig. 2). Ses tâches incluent l'identification primaire des événements reçus (si un traitement personnalisé des événements est requis ou non) et, si nécessaire, leur transfert vers son objet propriétaire (contrôle étendu), qui assure le routage des événements à travers la hiérarchie des objets conteneurs.

Script de création de contrôle

L'incorporation d'un contrôle dans un conteneur comprend trois phases : la création d'un objet ActiveX, son initialisation et son activation.

Les contrôles sont créés dans l'espace d'adressage du conteneur à l'aide de caractéristiques standards COM, par exemple CoCreateInstance. L'identifiant de classe global unique correspondant, CLSID, est transmis à la fonction en tant qu'identifiant de contrôle. Il convient de noter que le conteneur doit prendre en charge diverses options pour identifier les objets COM dans le système - comme un identifiant de programme ProgID, un identifiant de classe unique sous la forme d'une chaîne, etc.

L'objectif principal de la phase d'initialisation est de transférer au contrôle, via la fonction IOleObject::SetClientSite, un pointeur vers l'interface IOleClientSite de l'objet de communication et d'appeler la fonction IPersistStreamInit::InitNew ou IPersistStreamInit::Load (selon que le l'objet est chargé depuis le stockage ou non). Le passage d'un pointeur vers l'interface IOleClientSite vers l'objet peut se produire avant le chargement/initialisation ou après ; le moment de la transmission est déterminé par la présence de l'attribut OLEMISC_SETCLIENTSITEFIRST (IOleObject::GetMiscStatus). Ceci est important car le moment où le pointeur est passé détermine à quel moment le contrôle recevra les valeurs des propriétés ambiantes du conteneur. Si ce signe est ignoré, le fonctionnement ultérieur de l'objet ActiveX peut être incorrect.

Cette phase implique ensuite une première initialisation des propriétés du contrôle étendu qui complète l'objet ActiveX en cours de création. Par exemple, vous devez définir correctement le nom de l'objet (initialiser la propriété Name, qui assure l'identification des contrôles au sein du conteneur). Tout contrôle intégré dans un conteneur programmable doit prendre en charge cette propriété, mais il s'agit toujours d'une propriété du conteneur. Souvent, par défaut, les objets reçoivent le nom court de la classe à laquelle ils appartiennent (ce nom est renvoyé par la méthode IOleObject::GetUserType pour le paramètre USERCLASSTYPE_SHORT), suivi d'un index numérique, qui garantit que les noms des contrôles au sein de le conteneur est unique. Si vous ne pouvez pas obtenir le nom spécifié ou s'il ne satisfait pas à la logique du conteneur, vous pouvez spécifier un nom prédéfini avec l'index correspondant.

L'activation d'un contrôle implique une certaine séquence d'actions. La première chose à faire est de configurer le retour de l'objet ActiveX vers l'objet de communication dans le conteneur (site de contrôle). Pour ce faire, la méthode IOleObject::Advise est appelée, à laquelle est passé en paramètre un pointeur vers l'interface standard de l'objet de communication IAdviseSink. Ensuite, vous devez demander correctement l'interface de la famille IViewObject (selon la spécification, un objet ActiveX peut prendre en charge les interfaces IViewObject, IViewObject2, IViewObjectEx, qui sont dans la hiérarchie d'héritage) et définir des commentaires pour cela en appelant IViewObject : Méthode SetAdvise passant un pointeur vers IAdviseSink. De plus, vous devez indiquer au contrôle le nom de son conteneur (cela est implémenté en appelant la méthode IOleObject::SetHostName), demander et enregistrer toutes les interfaces nécessaires au bon fonctionnement de l'objet ActiveX (au moins IOleInPlaceObject et IOleControl). La dernière chose que vous devez faire pour restituer visuellement le contrôle est d’appeler la fonction IOleObject::DoVerb* avec le paramètre OLEIVERB_INPLACEACTIVATE.

*Dans l'implémentation ATL, cette fonction est, entre autres, chargée de créer une fenêtre pour les contrôles réguliers (fenêtrés).

Script de suppression de contrôle

Pour supprimer de la mémoire un contrôle incorporé dans un conteneur, vous devez exclure son objet d'association de contrôle correspondant de la collection, puis effectuer deux opérations en séquence : break retour et libérer les pointeurs stockés vers les interfaces d'objets ActiveX.

Pour rompre les liens de rétroaction, vous devez d'abord informer l'élément en cours de suppression de la nécessité de libérer (en appelant la méthode IUnknown::Release) les pointeurs qu'il détient vers l'interface IAdviseSink de l'objet de communication. Pour ce faire, les méthodes IViewObject::SetAdvise (en passant NULL comme argument) et IOleObject::Unadvise sont appelées, auxquelles vous devez fournir l'identifiant de connexion enregistré lors de l'activation. Ensuite, vous devez activer la procédure de désinitialisation des objets ActiveX (en appelant la fonction IOleObject::Close). L’étape suivante consiste à indiquer au contrôle de libérer le pointeur vers l’interface IOleClientSite en appelant IOleObject::SetClientSite avec le paramètre NULL.

La phase de libération des pointeurs stockés vers les interfaces de contrôle implique l’appel séquentiel de la méthode Release sur celles-ci. Dès que le dernier pointeur est libéré, l'objet (conformément à la technologie COM) sera supprimé de la RAM.

Enregistrer et charger le script

Enregistrer un objet conteneur dans le stockage, quel que soit le type de ce dernier, signifie enregistrer les propriétés du conteneur (par exemple, les propriétés d'environnement) et l'ensemble des contrôles intégrés, c'est-à-dire les identifiants et les propriétés (y compris celles étendues) de chaque objet appartenant à la collection. L'identifiant d'élément de contrôle peut être un identifiant de classe globalement unique (CLSID). Cela vous permettra de créer l'objet ActiveX requis au stade de l'initialisation et de le charger avec les données contenues dans le stockage après l'identifiant spécifié. Pour enregistrer les propriétés d'un élément de contrôle, par exemple dans un flux, la méthode Save de l'interface objet ActiveX standard IPersistStreamInit est appelée. Pour charger, la méthode Load de la même interface est appelée.

Cette procédure de sauvegarde assure la restauration ultérieure de l'objet conteneur depuis le stockage. La méthode décrite fonctionne bien à condition qu'entre le moment de la sauvegarde et le moment du chargement, il n'y ait aucun changement de version ni suppression de contrôles du système. De telles situations surviennent souvent lors du déplacement du stockage de données d'un ordinateur à un autre sur lequel les objets ActiveX enregistrés n'ont pas été installés ou enregistrés. Dans ce cas, le chargement d'un objet conteneur à partir du stockage entraînera soit un arrêt fatal du programme, soit une erreur lors du chargement de l'ensemble du conteneur dans son ensemble. Pour éviter les erreurs, il est nécessaire d'établir clairement la frontière entre les données des différents contrôles, en enregistrant dans le stockage après l'identifiant de l'objet la taille des informations enregistrées par celui-ci. Cela permettra à l'étape de chargement de se positionner précisément au début des données de chaque objet ActiveX, et également d'ignorer les contrôles qui ne sont pas enregistrés auprès du système, mais de charger l'objet conteneur dans son ensemble.

Interfaces de collecte d'objets ActiveX

Selon la norme, un conteneur de contrôle doit permettre aux objets ActiveX qui y sont intégrés d'interagir. Pour ce faire, vous devez prendre en charge l'interface IOleContainer, qui permet de lister tous les contrôles qui y sont insérés. S'il existe un contrôle étendu, l'énumération doit s'effectuer sur ses interfaces IUnknown, et non via les interfaces de l'objet de base.

Une interface de collection d'objets standard est utilisée pour fournir l'accès à la collection aux clients d'automatisation. La collection standard comprend les méthodes Add, Remove, Clear et Item ainsi que les propriétés _NewEnum et Count, qui fournissent une itération complète sur les éléments. Par exemple, la construction Visual Basic pour chaque utilise la propriété _NewEnum pour énumérer les éléments, et la construction pour la prochaine utilise la propriété Count et la méthode Item. Dans le langage Object RSL, la propriété _NewEnum est utilisée lors de l'accès méthode standard Objet ActiveX CreateEnum. Ceci est illustré par exemple par un programme RSL qui imprime, selon la méthode spécifiée, les noms des fichiers ouverts dans l'application. Microsoft Excel(son texte est donné ci-dessous).

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

Les scénarios considérés permettent de développer des fonctions permettant d'ajouter un contrôle à un conteneur et de l'en supprimer. Dans la plupart des cas, la fonction add crée un objet de connexion avec le contrôle (qui stocke tous les pointeurs vers les interfaces de l'objet ActiveX nécessaires au fonctionnement) et appelle une fonction similaire dessus. Ce dernier réalise à son tour le scénario de mise en œuvre décrit ci-dessus (éventuellement sans la phase d'activation). Si la formation d'un objet ActiveX dans la RAM a réussi, la fonction conteneur ajoute l'objet de communication correspondant à la collection. Souvent, en raison de leur similitude, les procédures d'intégration et de chargement d'un contrôle depuis le référentiel sont combinées.

* * *

Nous avons examiné ici les principales problématiques liées à la construction de conteneurs de contrôle : implémentation, affichage visuel, sauvegarde et chargement d'un objet ActiveX, ainsi que sa suppression correcte de la RAM. Cependant, lors du processus de création d'un environnement d'outils graphiques, nous devions implémenter plusieurs conteneurs qui différaient les uns des autres par les interfaces d'automatisation qu'ils fournissaient, les sous-ensembles d'objets ActiveX autorisés pour l'implémentation, les ensembles de propriétés, méthodes et événements d'extension. contrôles, etc À cette fin, un modèle a été proposé qui permet la création de divers éléments de conteneur et s'intègre bien à la bibliothèque ATL. L'indépendance vis-à-vis d'interfaces spécifiques est obtenue grâce à l'utilisation de classes modèles dont les paramètres sont ces interfaces.

*Par exemple, un contrôle Tab est un conteneur de pages de propriétés, qui sont des conteneurs à usage général.

Ce modèle vous permet de créer rapidement des versions de base de divers objets ActiveX dotés d'une « logique de conteneur ». De plus, l'infrastructure mise en œuvre permet la création de conteneurs qui ne sont pas des contrôles. Un tel conteneur peut être placé comme Fenêtres Windows dans n'importe quelle partie de l'application en cours de développement, puis, en envoyant des messages appropriés, y implémentez divers contrôles.

Le résultat est une architecture assez flexible pour créer des conteneurs, avec laquelle vous pouvez créer un assistant qui s'étend Fonctionnalité Environnement Microsoft Visual Studio au mécanisme de génération de squelette de conteneur.


La modification manuelle du registre Windows pour supprimer les clés d'erreur avec l'erreur 800A01AD n'est pas recommandée, sauf si vous êtes un professionnel du service informatique. Des erreurs commises lors de la modification du registre peuvent entraîner l'inopérabilité de votre PC et causer des dommages irréparables à votre ordinateur. système opérateur. En fait, même une virgule placée au mauvais endroit peut empêcher votre ordinateur de démarrer !

En raison de ce risque, nous vous recommandons fortement d'utiliser un nettoyeur de registre fiable tel que WinThruster [Téléchargement] (développé par un partenaire certifié Microsoft Gold) pour analyser et réparer tout problème de registre lié à l'erreur 800A01AD. À l'aide de Registry Cleaner [Télécharger], vous pouvez automatiser le processus de recherche des entrées de registre corrompues, des références de fichiers manquantes (telles que celles à l'origine de l'erreur %%error_name%%) et des liens rompus dans le registre. Avant chaque scan, un copie de sauvegarde, qui vous permet d'annuler toute modification en un seul clic et vous protège contre d'éventuels dommages à votre ordinateur. La meilleure partie est que la correction des erreurs de registre [Télécharger] peut considérablement améliorer la vitesse et les performances du système.


Avertissement: Si tu n'es pas utilisateur expérimenté PC, nous NE recommandons PAS de modifier manuellement le registre Windows. Une utilisation incorrecte de l'Éditeur du Registre peut entraîner de graves problèmes et nécessiter Réinstallation de Windows. Nous ne garantissons pas que les problèmes résultant d'une utilisation incorrecte de l'Éditeur du Registre puissent être corrigés. Vous utilisez l'Éditeur du Registre à vos propres risques.

Avant de restaurer manuellement Registre Windows, vous devez créer une sauvegarde en exportant la partie du registre liée à l'erreur 800A01AD (par exemple, ActiveX) :

  1. Cliquez sur le bouton Commencer.
  2. Entrer " commande"V barre de recherche... NE CLIQUEZ PAS ENCORE ENTRER!
  3. Tout en maintenant les touches enfoncées CTRL-Maj sur votre clavier, appuyez sur ENTRER.
  4. Une boîte de dialogue d'accès s'affichera.
  5. Cliquez sur Oui.
  6. La boîte noire s'ouvre avec un curseur clignotant.
  7. Entrer " regedit" et appuyez sur ENTRER.
  8. Dans l'Éditeur du Registre, sélectionnez la clé liée à l'erreur 800A01AD (par exemple, ActiveX) que vous souhaitez sauvegarder.
  9. au menu Déposer sélectionner Exporter.
  10. Sur la liste Enregistrer dans sélectionnez le dossier dans lequel vous souhaitez enregistrer la sauvegarde de la clé ActiveX.
  11. Sur le terrain Nom de fichier Entrez un nom pour le fichier de sauvegarde, par exemple "Sauvegarde ActiveX".
  12. Assurez-vous que le champ Plage d'exportation valeur sélectionnée Branche sélectionnée.
  13. Cliquez sur Sauvegarder.
  14. Le fichier sera enregistré avec extension .reg.
  15. Vous avez maintenant une copie de votre entrée de registre associée à ActiveX.

Les étapes suivantes pour modifier manuellement le registre ne seront pas décrites dans cet article, car elles sont susceptibles d'endommager votre système. Si vous souhaitez plus d'informations sur la modification manuelle du registre, veuillez consulter les liens ci-dessous.

gastrogourou 2017