Debuggerdatenmodell C++-Skripterstellung
In diesem Thema wird beschrieben, wie Sie das Debuggerdatenmodell C++-Debuggerdatenmodell-C++-Skripting verwenden, um die Automatisierung mit der Debugger-Engine mithilfe von Skripts zu unterstützen.
Skriptverwaltung im Debuggerdatenmodell
Neben der Rolle des Datenmodell-Managers als zentrale Autorität für die Objekterstellung und -erweiterbarkeit ist er auch für die Verwaltung eines abstrakten Konzepts von Skripts verantwortlich. Aus sicht des Skript-Managers-Teils des Datenmodell-Managers ist ein Skript etwas, das dynamisch von einem Anbieter geladen, entladen und möglicherweise debuggen kann, um das Datenmodell zu erweitern oder neue Funktionen für das Datenmodell bereitzustellen.
Ein Skriptanbieter ist eine Komponente, die eine Sprache (z. B. NatVis, JavaScript usw.) mit dem Datenmodell überbrückt. Es registriert eine oder mehrere Dateierweiterungen (z. B.: ". NatVis", ".js"), die vom Anbieter verarbeitet werden, sodass ein Debuggerclient oder eine Benutzeroberfläche das Laden von Skriptdateien mit dieser bestimmten Erweiterung durch Delegierung an den Anbieter ermöglicht.
Der Hauptskript-Manager: IDataModelScriptManager
Die Hauptschnittstelle des Skript-Managers ist wie folgt definiert.
DECLARE_INTERFACE_(IDataModelScriptManager, IUnknown)
{
STDMETHOD(GetDefaultNameBinder)(_COM_Outptr_ IDataModelNameBinder **ppNameBinder) PURE;
STDMETHOD(RegisterScriptProvider)(_In_ IDataModelScriptProvider *provider) PURE;
STDMETHOD(UnregisterScriptProvider)(_In_ IDataModelScriptProvider *provider) PURE;
STDMETHOD(FindProviderForScriptType)(_In_ PCWSTR scriptType, _COM_Outptr_ IDataModelScriptProvider **provider) PURE;
STDMETHOD(FindProviderForScriptExtension)(_In_ PCWSTR scriptExtension, _COM_Outptr_ IDataModelScriptProvider **provider) PURE;
STDMETHOD(EnumerateScriptProviders)(_COM_Outptr_ IDataModelScriptProviderEnumerator **enumerator) PURE;
}
Die GetDefaultNameBinder-Methode gibt den Standardnamenbinder des Datenmodells zurück. Eine Namensbindung ist eine Komponente, die einen Namen im Kontext eines Objekts auflöst. Bei instance wird unter Dem Ausdruck "foo.bar" eine Namensbindung aufgerufen, um die Namensleiste im Kontext von Objekt foo aufzulösen. Der hier zurückgegebene Binder folgt einem Satz von Standardregeln für das Datenmodell. Skriptanbieter können diese Bindung verwenden, um Konsistenz bei der Namensauflösung für anbieterübergreifend zu gewährleisten.
Die RegisterScriptProvider-Methode informiert das Datenmodell darüber, dass ein neuer Skriptanbieter vorhanden ist, der in der Lage ist, eine neue Sprache mit dem Datenmodell zu überbrücken. Wenn diese Methode aufgerufen wird, ruft der Skript-Manager sofort den angegebenen Skriptanbieter zurück und fragt nach den Eigenschaften der von ihm verwalteten Skripts. Wenn bereits ein Anbieter unter dem Namen oder der Dateierweiterung registriert ist, den der angegebene Skriptanbieter angibt, schlägt diese Methode fehl. Nur ein einzelner Skriptanbieter kann als Handler für einen bestimmten Namen oder eine bestimmte Dateierweiterung registriert werden.
Die UnregisterScriptProvider-Methode hebt einen Aufruf der RegisterScriptProvider-Methode auf. Der Name und die Dateierweiterung, die vom inpassierten Skriptanbieter angegeben werden, werden ihm nicht mehr zugeordnet. Es ist wichtig zu beachten, dass auch nach der Aufhebung der Registrierung möglicherweise eine beträchtliche Anzahl ausstehender COM-Verweise auf den Skriptanbieter vorhanden ist. Diese Methode verhindert nur das Laden/Erstellen von Skripts des Typs, den der angegebene Skriptanbieter verwaltet. Wenn ein von diesem Anbieter geladenes Skript weiterhin geladen wird oder das Objektmodell des Debuggers (oder Datenmodells) bearbeitet hat, können diese Bearbeitungen weiterhin Verweise auf das Skript enthalten. Es kann Datenmodelle, Methoden oder Objekte geben, die direkt auf Konstrukte im Skript verweisen. Ein Skriptanbieter muss darauf vorbereitet sein, dies zu behandeln.
Die FindProviderForScriptType-Methode durchsucht den Skript-Manager nach einem Anbieter, der über eine Skripttypzeichenfolge verfügt, wie in dieser Methode angegeben. Wenn eine nicht gefunden werden kann, schlägt diese Methode fehl. Andernfalls wird ein solcher Skriptanbieter an den Aufrufer zurückgegeben.
Die EnumerateScriptProviders-Methode gibt einen Enumerator zurück, der jeden Skriptanbieter aufzählt, der über einen vorherigen Aufruf der RegisterScriptProvider-Methode beim Skript-Manager registriert wurde.
Skriptanbieteraufzählung: IDataModelScriptProviderEnumerator
Die EnumerateScriptProviders-Methode gibt einen Enumerator der folgenden Form zurück:
DECLARE_INTERFACE_(IDataModelScriptProviderEnumerator, IUnknown)
{
STDMETHOD(Reset)() PURE;
STDMETHOD(GetNext)(_COM_Outptr_ IDataModelScriptProvider **provider) PURE;
}
Mit der Reset-Methode wird der Enumerator an die Position verschoben, an der er sich vor der Rückgabe des ersten Elements befand.
Die GetNext-Methode verschebt den Enumerator um ein Element nach vorne und gibt den Skriptanbieter zurück, der sich bei diesem Element befindet. Wenn der Enumerator das Ende der Enumeration erreicht, wird E_BOUNDS zurückgegeben. Beim Aufrufen der GetNext-Methode nach dem Empfang dieses Fehlers wird weiterhin E_BOUNDS auf unbestimmte Zeit zurückgegeben.
Debuggerdatenmodell C++-Hostschnittstellen für Skripterstellung
Die Rolle des Hosts bei der Skripterstellung
Der Debughost macht eine Reihe von Schnittstellen auf sehr niedriger Ebene verfügbar, um die Art des Typsystems seiner Debugziele zu verstehen, Ausdrücke in der Sprache seiner Debugziele auszuwerten usw. Normalerweise ist es nicht mit Konstrukten auf höherer Ebene wie Skripts zu bekünden. Dies bleibt der gesamten Debuggeranwendung oder Erweiterungen überlassen, die diese Funktionen bereitstellen. Es gibt jedoch eine Ausnahme. Jeder Debughost, der an der gesamten Skripterstellungsoberfläche des Datenmodells teilnehmen möchte, muss einige einfache Schnittstellen implementieren, um Kontexte für Skripts bereitzustellen. Tatsächlich kann der Debughost steuern, wo die Skriptumgebung Funktionen und andere bereitgestellte Skriptfunktionen im Namespace des Datenmodells platzieren soll. Die Beteiligung an diesem Prozess ermöglicht es dem Host, die Verwendung solcher Funktionen in seinem Ausdrucksauswertungs-Evaluator für instance zuzulassen (oder nicht). Aus Sicht des Hosts sind hier folgende Schnittstellen beteiligt:
Schnittstelle | Beschreibung |
---|---|
IDebugHostScriptHost | Die Schnittstelle, die die Fähigkeit des Debughosts angibt, an der Skriptumgebung teilzunehmen. Diese Schnittstelle ermöglicht die Erstellung von Kontexten, die Skript-Engines darüber informieren, wo Objekte platziert werden sollen. |
IDataModelScriptHostContext | Eine Hostschnittstelle, die vom Skriptanbieter als Container für den Inhalt des Skripts verwendet wird. Wie der Inhalt eines Skripts anders als die Bearbeitungen, die es für das Objektmodell der Debuggeranwendung ausführt, angezeigt wird, hängt vom jeweiligen Debughost ab. Diese Schnittstelle ermöglicht es dem Skriptanbieter, Informationen darüber abzurufen, wo der Inhalt platziert werden soll. Weitere Informationen finden Sie weiter unten in diesem Thema unter Datenmodell-C++-Skriptschnittstellen . |
Der Skripthost des Debughosts: IDebugHostScriptHostHost
Die IDebugHostScriptHost-Schnittstelle ist die Schnittstelle, die von einem Skriptanbieter verwendet wird, um einen Kontext vom Debughost für ein neu erstelltes Skript abzurufen. Dieser Kontext enthält ein -Objekt (vom Debughost bereitgestellt), in dem der Skriptanbieter alle Brücken zwischen dem Datenmodell und der Skriptumgebung platzieren kann. Solche Brücken können für instance Datenmodellmethoden sein, die Skriptfunktionen aufrufen. Dadurch kann ein Aufrufer auf der Datenmodellseite Skriptmethoden aufrufen, indem die Call-Methode auf der IModelMethod-Schnittstelle verwendet wird.
Die IDebugHostScriptHost-Schnittstelle ist wie folgt definiert.
DECLARE_INTERFACE_(IDebugHostScriptHost, IUnknown)
{
STDMETHOD(CreateContext)(_In_ IDataModelScript* script, _COM_Outptr_ IDataModelScriptHostContext** scriptContext) PURE;
}
Die CreateContext-Methode wird von einem Skriptanbieter aufgerufen, um einen neuen Kontext zu erstellen, in dem der Inhalt des Skripts platziert werden soll. Dieser Kontext wird durch die IDataModelScriptHostContext-Schnittstelle dargestellt, die auf der Seite Datenmodell-C++-Skriptschnittstellen ausführlich beschrieben wird.
Debuggerdatenmodell-C++-Skriptschnittstellen
Skript- und Skriptschnittstellen
Die Allgemeine Architektur des Datenmodells ermöglicht es einem Drittanbieter, eine Brücke zwischen einer Sprache und dem Objektmodell des Datenmodells zu definieren. In der Regel handelt es sich bei der überbrückten Sprache um eine Skriptsprache, da die Umgebung des Datenmodells sehr dynamisch ist. Eine Komponente, die diese Brücke zwischen einer Sprache und dem Objektmodell des Datenmodells definiert und implementiert, wird als Skriptanbieter bezeichnet. Bei der Initialisierung registriert sich ein Skriptanbieter beim Skript-Manager-Teil des Datenmodell-Managers, und jede Schnittstelle, die die Erweiterbarkeit verwaltet, ermöglicht anschließend das Bearbeiten, Laden, Entladen und möglicherweise Debuggen von Skripts, die in die Sprache geschrieben wurden, die vom Skriptanbieter verwaltet wird.
Beachten Sie, dass Debugtools für Windows derzeit zwei Skriptanbieter definieren.
- Der NatVis-Anbieter. Dieser Anbieter ist in DbgEng.dll eingebettet und überbrückt zwischen NatVis-XML und Datenmodellen, sodass die Visualisierung nativer/sprachsprachiger Datentypen ermöglicht wird.
- Der JavaScript-Anbieter. Dieser Anbieter ist in einer Legacydebuggererweiterung enthalten: JsProvider.dll. Es überbrückt Skripts, die in der JavaScript-Sprache geschrieben wurden, und dem Datenmodell, sodass beliebige Formen der Debuggersteuerung und -erweiterbar sind.
Es können neue Anbieter geschrieben werden, die andere Sprachen (z.B. Python usw.) mit dem Datenmodell verbinden. Dies wäre derzeit in Legacydebuggererweiterungen für Ladezwecke gekapselt. Der Skriptanbieter selbst sollte die Abhängigkeit von Legacy-Engine-Schnittstellen minimieren und nach Möglichkeit nur die Datenmodell-APIs verwenden. Dies ermöglicht es dem Anbieter, mit deutlich größerer Leichtigkeit in andere Umgebungen portierbar zu werden.
Es gibt zwei Klassen von Schnittstellen im Zusammenhang mit Skriptanbietern. Die erste Klasse von Schnittstellen ist für die allgemeine Verwaltung von Skriptanbietern und den von ihnen verwalteten Skripts vorgesehen. Die zweite Klasse von Schnittstellen dient zur Unterstützung des Skriptdebuggens. Während die Unterstützung für die erste Gruppe obligatorisch ist, ist die Unterstützung für die zweite Gruppe optional und möglicherweise nicht für jeden Anbieter sinnvoll.
Die allgemeinen Verwaltungsschnittstellen sind:
Schnittstelle | Beschreibung |
---|---|
IDataModelScriptProvider | Die Kernschnittstelle, die ein Skriptanbieter implementieren muss. Dies ist die Schnittstelle, die beim Skript-Manager-Teil des Datenmodell-Managers registriert wird, um die Unterstützung eines bestimmten Skripttyps durch den Anbieter anzukündigen und sich für eine bestimmte Dateierweiterung zu registrieren. |
IDataModelScript | Eine Abstraktion eines bestimmten Skripts, das vom Anbieter verwaltet wird. Jedes Skript, das geladen oder bearbeitet wird, verfügt über einen separaten IDataModelScript-instance |
IDataModelScriptClient | Eine Clientschnittstelle, die vom Skriptanbieter verwendet wird, um Informationen an eine Benutzeroberfläche zu übermitteln. Skriptanbieter implementieren diese Schnittstelle nicht. Die Anwendung, die das Datenmodell hostet, das Skriptanbieter verwenden möchte, tut dies. Ein Skriptanbieter ruft Methoden des Skriptclients auf, um status, Fehler usw. zu melden... |
IDataModelScriptHostContext | Eine Hostschnittstelle, die vom Skriptanbieter als Container für den Inhalt des Skripts verwendet wird. Wie der Inhalt einer Skriptoberfläche anders als die Bearbeitungen, die sie am Objektmodell der Debuggeranwendung ausführt, hängt vom jeweiligen Debughost ab. Diese Schnittstelle ermöglicht es dem Skriptanbieter, Informationen darüber abzurufen, wo der Inhalt platziert werden soll. |
IDataModelScriptTemplate | Skriptanbieter können eine oder mehrere Vorlagen bereitstellen, die als Ausgangspunkte für Benutzer zum Erstellen von Skripts dienen. Eine Debuggeranwendung, die einen integrierten Editor bereitstellt, kann neue Skripts mit Vorlageninhalten vorab ausfüllen, wie vom Anbieter über diese Schnittstelle angekündigt. |
IDataModelScriptTemplateEnumerator | Eine Enumeratorschnittstelle, die der Skriptanbieter implementiert, um alle unterstützten Vorlagen anzukündigen. |
IDataModelNameBinder | Ein Namensbinder – ein Objekt, das einen Namen in einem Kontext einem Wert zuordnen kann. Für einen bestimmten Ausdruck wie "foo.bar" kann ein Namensbinder den Namen "bar" im Kontext des Objekts "foo" binden und einen Wert oder Verweis darauf erzeugen. Namensbinder werden in der Regel nicht von einem Skriptanbieter implementiert. Stattdessen kann der Standardbinder aus dem Datenmodell abgerufen und vom Skriptanbieter verwendet werden. |
Die Debugschnittstellen sind:
Schnittstelle | Beschreibung |
---|---|
IDataModelScriptDebug | Die Kernschnittstelle, die ein Skriptanbieter bereitstellen muss, um ein Skript debuggen zu können. Die Implementierungsklasse der IDataModelScript-Schnittstelle muss QueryInterface für IDataModelScriptDebug sein, wenn das Skript debuggen kann. |
IDataModelScriptDebugClient | Die Benutzeroberfläche, die die Funktion des Skriptdebuggens bereitstellen möchte, implementiert die IDataModelScriptDebugClient-Schnittstelle. Der Skriptanbieter verwendet diese Schnittstelle, um Debuginformationen hin und her zu übergeben (z. B. Ereignisse, die auftreten, Breakpoints usw.) |
IDataModelScriptDebugStack | Der Skriptanbieter implementiert diese Schnittstelle, um den Begriff eines Aufrufstapels für den Skriptdebugger verfügbar zu machen. |
IDataModelScriptDebugStackFrame | Der Skriptanbieter implementiert diese Schnittstelle, um den Begriff eines bestimmten Stapelrahmens innerhalb des Aufrufstapels verfügbar zu machen. |
IDataModelScriptDebugVariableSetEnumerator | Der Skriptanbieter implementiert diese Schnittstelle, um eine Reihe von Variablen verfügbar zu machen. Dieser Satz kann den Satz von Parametern für eine Funktion, den Satz lokaler Variablen oder den Satz von Variablen innerhalb eines bestimmten Bereichs darstellen. Die genaue Bedeutung hängt davon ab, wie die Schnittstelle abgerufen wurde. |
IDataModelScriptDebugBreakpoint | Der Skriptanbieter implementiert diese Schnittstelle, um den Begriff und die Steuerung eines bestimmten Haltepunkts innerhalb des Skripts verfügbar zu machen. |
IDataModelScriptDebugBreakpointEnumerator | Der Skriptanbieter implementiert dies, um alle Haltepunkte aufzulisten, die derzeit im Skript vorhanden sind (unabhängig davon, ob sie aktiviert sind oder nicht). |
Der Kernskriptanbieter: IDataModelScriptProvider
Jede Erweiterung, die ein Skriptanbieter sein möchte, muss eine Implementierung der IDataModelScriptProvider-Schnittstelle bereitstellen und diese über die RegisterScriptProvider-Methode beim Skript-Manager-Teil des Datenmodell-Managers registrieren. Diese Kernschnittstelle, die implementiert werden muss, wird wie folgt definiert.
DECLARE_INTERFACE_(IDataModelScriptProvider, IUnknown)
{
STDMETHOD(GetName)(_Out_ BSTR *name) PURE;
STDMETHOD(GetExtension)(_Out_ BSTR *extension) PURE;
STDMETHOD(CreateScript)(_COM_Outptr_ IDataModelScript **script) PURE;
STDMETHOD(GetDefaultTemplateContent)(_COM_Outptr_ IDataModelScriptTemplate **templateContent) PURE;
STDMETHOD(EnumerateTemplates)(_COM_Outptr_ IDataModelScriptTemplateEnumerator **enumerator) PURE;
}
Die GetName-Methode gibt den Namen des Typs (oder der Sprache) von Skripts zurück, den der Anbieter als Zeichenfolge verwaltet, die über die SysAllocString-Methode zugeordnet ist. Der Aufrufer ist für das Freigeben der zurückgegebenen Zeichenfolge über SysFreeString verantwortlich. Beispiele für Zeichenfolgen, die von dieser Methode zurückgegeben werden können, sind "JavaScript" oder "NatVis". Die zurückgegebene Zeichenfolge wird wahrscheinlich in der Benutzeroberfläche der Debuggeranwendung angezeigt, die das Datenmodell hostet. Keine zwei Skriptanbieter geben denselben Namen zurück (ohne Beachtung der Groß-/Kleinschreibung).
Die GetExtension-Methode gibt die Dateierweiterung für Skripts zurück, die von diesem Anbieter (ohne punkt) verwaltet werden, als Zeichenfolge, die über die SysAllocString-Methode zugeordnet wird. Die Debuggeranwendung, die das Datenmodell hostt (mit Skriptunterstützung), delegiert das Öffnen von Skriptdateien mit dieser Erweiterung an den Skriptanbieter. Der Aufrufer ist für das Freigeben der zurückgegebenen Zeichenfolge über SysFreeString verantwortlich. Beispiele für Zeichenfolgen, die von dieser Methode zurückgegeben werden können, sind "js" oder "NatVis".
Die CreateScript-Methode wird aufgerufen, um ein neues Skript zu erstellen. Der Skriptanbieter muss ein neues und leeres Skript zurückgeben, das von der zurückgegebenen IDataModelScript-Schnittstelle dargestellt wird, wenn diese Methode aufgerufen wird. Beachten Sie, dass diese Methode aufgerufen wird, unabhängig davon, ob eine Benutzeroberfläche ein neues leeres Skript zum Bearbeiten durch den Benutzer erstellt oder ob die Debuggeranwendung ein Skript vom Datenträger lädt. Der Anbieter beteiligt sich nicht an Datei-E/A. Es verarbeitet lediglich die Anforderungen von der Hostinganwendung über Streams, die an Methoden in IDataModelScript übergeben werden.
Die GetDefaultTemplateContent-Methode gibt eine Schnittstelle für den Standardvorlageninhalt des Anbieters zurück. Dies sind Inhalte, die der Skriptanbieter in einem Bearbeitungsfenster für ein neu erstelltes Skript vorab auffüllen möchte. Wenn der Skriptanbieter über keine Vorlagen verfügt (oder über keinen Vorlageninhalt verfügt, der als Standardinhalt festgelegt ist), gibt der Skriptanbieter möglicherweise E_NOTIMPL von dieser Methode zurück.
Die EnumerateTemplates-Methode gibt einen Enumerator zurück, der in der Lage ist, die Vielzahl von Vorlagen aufzulisten, die vom Skriptanbieter bereitgestellt werden. Der Vorlageninhalt möchte beim Erstellen eines neuen Skripts in ein Bearbeitungsfenster "vorab ausgefüllt" werden. Wenn mehrere verschiedene Vorlagen unterstützt werden, können diese Vorlagen benannt werden (z. B. "Imperatives Skript", "Erweiterungsskript"), und die Debuggeranwendung, die das Datenmodell hosten, kann auswählen, wie die "Vorlagen" dem Benutzer präsentiert werden sollen.
Die Kernskriptschnittstelle: IDataModelScript
Die Standard-Schnittstelle, die ein einzelnes Skript verwaltet, das vom Anbieter implementiert wird, ist die IDataModelScript-Schnittstelle. Eine Komponente, die diese Schnittstelle implementiert, wird zurückgegeben, wenn der Client ein neues leeres Skript erstellen und die CreateScript-Methode für IDataModelScriptProvider aufruft.
Jedes vom Anbieter erstellte Skript sollte sich in einem unabhängigen Silo befinden. Ein Skript sollte sich nicht auf ein anderes Skript auswirken können, außer durch explizite Interaktion mit externen Objekten über das Datenmodell. Zwei Skripts können für instance beide einen Typ oder ein Konzept erweitern (z. B. die Vorstellung des Debuggers, was ein Prozess ist). Beide Skripts können dann über das externe Prozessobjekt auf die Felder des jeweils anderen zugreifen.
Die Schnittstelle wird wie folgt definiert.
DECLARE_INTERFACE_(IDataModelScript, IUnknown)
{
STDMETHOD(GetName)(_Out_ BSTR *scriptName) PURE;
STDMETHOD(Rename)(_In_ PCWSTR scriptName) PURE;
STDMETHOD(Populate)(_In_ IStream *contentStream) PURE;
STDMETHOD(Execute)(_In_ IDataModelScriptClient *client) PURE;
STDMETHOD(Unlink)() PURE;
STDMETHOD(IsInvocable)(_Out_ bool *isInvocable) PURE;
STDMETHOD(InvokeMain)(_In_ IDataModelScriptClient *client) PURE;
}
Die GetName-Methode gibt den Namen des Skripts als zugeordnete Zeichenfolge über die SysAllocString-Funktion zurück. Wenn das Skript noch keinen Namen hat, sollte die Methode einen NULL-BSTR zurückgeben. Unter diesen Umständen sollte sie nicht scheitern. Wenn das Skript über einen Aufruf der Rename-Methode explizit umbenannt wird, sollte die GetName-Methode den neu zugewiesenen Namen zurückgeben.
Die Rename-Methode weist dem Skript einen neuen Namen zu. Es liegt in der Verantwortung der Skriptimplementierung, diesen Namen zu speichern und bei jedem Aufruf der GetName-Methode zurückzugeben. Dies wird häufig aufgerufen, wenn eine Benutzeroberfläche das Skript unter einem neuen Namen speichern als auswäht. Beachten Sie, dass sich die Umbenennung des Skripts darauf auswirken kann, wo die Hostinganwendung den Inhalt des Skripts projiziert.
Die Populate-Methode wird vom Client aufgerufen, um den "Inhalt" des Skripts zu ändern oder zu synchronisieren. Es ist die Benachrichtigung, die an den Skriptanbieter gesendet wird, dass der Code des Skripts geändert wurde. Es ist wichtig zu beachten, dass diese Methode keine Ausführung des Skripts oder Änderungen an den Objekten verursacht, die das Skript bearbeitet. Dies ist lediglich eine Benachrichtigung an den Skriptanbieter, dass sich der Inhalt des Skripts geändert hat, sodass er seinen eigenen internen Zustand synchronisieren kann.
Die Execute-Methode führt den Inhalt des Skripts gemäß dem letzten erfolgreichen Populate-Aufruf aus und ändert das Objektmodell des Debuggers entsprechend diesem Inhalt. Wenn die Sprache (oder der Skriptanbieter) eine "Standard-Funktion" definiert , die der Autor beim Klicken auf eine imaginäre Schaltfläche "Skript ausführen" in einer Benutzeroberfläche aufrufen möchte, wird eine solche "Standard-Funktion" während eines Ausführungsvorgangs nicht aufgerufen. Der Execute-Vorgang kann als nur Initialisierungs- und Objektmodellbearbeitungen betrachtet werden (z. B. Das Ausführen von Stammcode und das Einrichten von Erweiterbarkeitspunkten).
Die Unlink-Methode hebt den Execute-Vorgang auf. Alle während der Ausführung des Skripts festgestellten Objektmodellmanipulationen oder Erweiterbarkeitspunkte werden aufgehoben. Nach einem Vorgang zum Aufheben der Verknüpfung kann das Skript über einen Aufruf von Execute erneut ausgeführt oder freigegeben werden.
Die IsInvocable-Methode gibt zurück, ob das Skript unwiderruflich ist oder nicht, d. h. ob es eine "Standard-Funktion" hat, die von der Sprache oder dem Anbieter definiert ist. Eine solche "Standard-Funktion" ist konzeptionell etwas, das der Skriptautor aufrufen würde, wenn eine imaginäre Schaltfläche "Skript ausführen" in einer Benutzeroberfläche gedrückt würde.
Wenn das Skript über eine "Standard-Funktion" verfügt, die über einen Benutzeroberflächenaufruf ausgeführt werden soll, wird dies über eine true-Rückgabe der IsInvocable-Methode angegeben. Die Benutzeroberfläche kann dann die InvokeMain-Methode aufrufen, um das Skript tatsächlich aufzurufen. Beachten Sie, dass sich dies von Execute unterscheidet, das den gesamten Stammcode ausführt und das Skript mit dem Namespace des zugrunde liegenden Hosts überbrückt.
**Der Skriptclient: IDataModelScriptClient **
Eine Anwendung, die das Datenmodell hostet, die Skripts verwalten möchte und über eine Benutzeroberfläche (grafische oder konsolen) um dieses Konzept herum verfügen soll, implementiert die IDataModelScriptClient-Schnittstelle. Diese Schnittstelle wird während der Ausführung oder beim Aufruf an einen beliebigen Skriptanbieter oder ein Skript übergeben, um Fehler- und Ereignisinformationen zurück an die Benutzeroberfläche zu übergeben.
Die IDataModelScriptClient-Schnittstelle ist wie folgt definiert.
DECLARE_INTERFACE_(IDataModelScriptClient, IUnknown)
{
STDMETHOD(ReportError)(_In_ ErrorClass errClass, _In_ HRESULT hrFail, _In_opt_ PCWSTR message, _In_ ULONG line, _In_ ULONG position) PURE;
}
Wenn während der Ausführung oder beim Aufrufen des Skripts ein Fehler auftritt, ruft der Skriptanbieter die ReportError-Methode auf, um die Benutzeroberfläche über den Fehler zu benachrichtigen.
Der Hostkontext für ein Skript: IDataModelScriptHostContext
Der Debughost hat einen gewissen Einfluss darauf, wie und wo er Datenmodellskriptinhalte projiziert. Es wird erwartet, dass jedes Skript den Host nach einem Kontext fragt, in dem Brücken zum Skript platziert werden sollen (z. B. Funktionsobjekte, die aufgerufen werden können usw.). Dieser Kontext wird durch Aufrufen der CreateContext-Methode auf IDebugHostScriptHost und Abrufen eines IDataModelScriptHostContext abgerufen.
Die IDataModelScriptHostContext-Schnittstelle ist wie folgt definiert.
DECLARE_INTERFACE_(IDataModelScriptHostContext, IUnknown)
{
STDMETHOD(NotifyScriptChange)(_In_ IDataModelScript* script, _In_ ScriptChangeKind changeKind) PURE;
STDMETHOD(GetNamespaceObject)(_COM_Outptr_ IModelObject** namespaceObject) PURE;
}
Es ist erforderlich, dass ein Skriptanbieter den Debughost über bestimmte Vorgänge benachrichtigt, die mit einem Methodenaufruf der NotifyScriptChange-Methode im zugeordneten Kontext auftreten. Solche Vorgänge werden als Member der ScriptChangeKind-Enumeration definiert.
Die GetNamespaceObject-Methode gibt ein Objekt zurück, in das der Skriptanbieter beliebige Brücken zwischen dem Datenmodell und dem Skript platzieren kann. Hier kann der Skriptanbieter für instance Datenmodellmethodenobjekte (IModelMethod-Schnittstellen in IModelObject eingeschachtelt) platzieren, deren Implementierung in entsprechend benannte Funktionen im Skript aufruft.
Vorlagen für neu erstellte Skripts: IDataModelScriptTemplate
Skriptanbieter, die vorab ausgefüllte Inhalte für neue Skripts (z. B. zur Unterstützung von Benutzern beim Schreiben von Skripts in einer Debugger-Benutzeroberfläche) präsentieren möchten, können dazu eine oder mehrere Skriptvorlagen bereitstellen. Solche Vorlagen sind Komponenten, die die IDataModelScriptTemplate-Schnittstelle implementieren und entweder über die GetDefaultTemplate-Methode oder die EnumerateTemplates-Methode für den Skriptanbieter zurückgegeben werden.
Die IDataModelScriptTemplate-Schnittstelle ist wie folgt definiert.
DECLARE_INTERFACE_(IDataModelScriptTemplate, IUnknown)
{
STDMETHOD(GetName)(_Out_ BSTR *templateName) PURE;
STDMETHOD(GetDescription)(_Out_ BSTR *templateDescription) PURE;
STDMETHOD(GetContent)(_COM_Outptr_ IStream **contentStream) PURE;
}
Die GetName-Methode gibt einen Namen der Vorlage zurück. Dies kann bei E_NOTIMPL fehlschlagen, wenn die Vorlage keinen Namen hat. Die einzelne Standardvorlage (sofern vorhanden) muss keinen Namen haben. Alle anderen Vorlagen sind vorhanden. Diese Namen können in einer Benutzeroberfläche als Teil eines Menüs angezeigt werden, um auszuwählen, welche Vorlage erstellt werden soll.
Die GetDescription-Methode gibt eine Beschreibung der Vorlage zurück. Eine solche Beschreibung wird dem Benutzer in aussagekräftigeren Schnittstellen angezeigt, um dem Benutzer zu helfen, zu verstehen, wofür die Vorlage entworfen wurde. Die Vorlage gibt möglicherweise E_NOTIMPL von dieser Methode zurück, wenn sie keine Beschreibung enthält.
Die GetContent-Methode gibt den Inhalt (oder Code) der Vorlage zurück. Dies ist, was im Bearbeitungsfenster vorab ausgefüllt wird, wenn ein Benutzer ausgewählt hat, ein neues Skript aus dieser Vorlage zu erstellen. Die Vorlage ist für das Erstellen (und Zurückgeben) eines Standardstreams über den Inhalt verantwortlich, den der Client pullen kann.
Enumeration des Vorlageninhalts eines Anbieters: IDataModelScriptTemplateEnumerator
Ein Skriptanbieter kann eine oder mehrere Vorlagen bereitstellen, die Inhalte auf einer Benutzeroberfläche vorab in neu erstellte Skripts ausfüllen. Wenn eine dieser Vorlagen bereitgestellt wird, muss der Skriptanbieter einen Enumerator für sie implementieren, der bei einem Aufruf der EnumerateTemplates-Methode zurückgegeben wird.
Ein solcher Enumerator ist eine Implementierung der IDataModelScriptTemplateEnumerator-Schnittstelle und wird wie folgt definiert.
DECLARE_INTERFACE_(IDataModelScriptTemplateEnumerator, IUnknown)
{
STDMETHOD(Reset)() PURE;
STDMETHOD(GetNext)(_COM_Outptr_ IDataModelScriptTemplate **templateContent) PURE;
}
Die Reset-Methode setzt den Enumerator an die Position zurück, an der er sich befand, als er zum ersten Mal erstellt wurde , bevor die erste Vorlage erstellt wurde.
Die GetNext-Methode verschiebt den Enumerator zur nächsten Vorlage und gibt sie zurück. Am Ende der Enumeration gibt der Enumerator E_BOUNDS zurück. Sobald die E_BOUNDS-Markierung erreicht wurde, erzeugt der Enumerator weiterhin E_BOUNDS Fehler auf unbestimmte Zeit, bis ein Reset-Aufruf erfolgt.
Auflösen der Bedeutung von Namen: IDataModelNameBinder
Das Datenmodell bietet eine Standardmethode für Skriptanbieter, um die Bedeutung eines bestimmten Namens in einem bestimmten Kontext zu bestimmen (z. B. die Bestimmung, was Balken für foo.bar bedeutet), die für eine Vielzahl von Skriptanbietern verwendet werden. Dieser Mechanismus wird als Namensbindung bezeichnet und durch die IDataModelNameBinder-Schnittstelle dargestellt. Ein solcher Binder kapselt eine Reihe von Regeln darüber, wie der Name aufgelöst wird und wie mit der Konfliktauflösung umgegangen wird, wenn ein Name mehrmals für ein Objekt definiert wird. Zu diesen Regeln gehört beispielsweise, wie ein projizierter Name (einer, der von einem Datenmodell hinzugefügt wird) mit einem systemeigenen Namen (einer im Typsystem der zu debuggenden Sprache) aufgelöst wird.
Um eine gewisse Konsistenz zwischen Skriptanbietern zu gewährleisten, stellt der Skript-Manager des Datenmodells einen Standardnamenbinder bereit. Diese Standardnamenbindung kann über einen Aufruf der GetDefaultNameBinder-Methode auf der IDataModelScriptManager-Schnittstelle abgerufen werden. Die Namensbinderschnittstelle ist wie folgt definiert.
DECLARE_INTERFACE_(IDataModelNameBinder, IUnknown)
{
STDMETHOD(BindValue)(_In_ IModelObject* contextObject, _In_ PCWSTR name, _COM_Errorptr_ IModelObject** value, _COM_Outptr_opt_result_maybenull_ IKeyStore** metadata) PURE;
STDMETHOD(BindReference)(_In_ IModelObject* contextObject, _In_ PCWSTR name, _COM_Errorptr_ IModelObject** reference, _COM_Outptr_opt_result_maybenull_ IKeyStore** metadata) PURE;
STDMETHOD(EnumerateValues)(_In_ IModelObject* contextObject, _COM_Outptr_ IKeyEnumerator** enumerator) PURE;
STDMETHOD(EnumerateReferences)(_In_ IModelObject* contextObject, _COM_Outptr_ IKeyEnumerator** enumerator) PURE;
}
Die BindValue-Methode führt das Äquivalent zu contextObject.name für das angegebene Objekt gemäß einer Reihe von Bindungsregeln aus. Das Ergebnis dieser Bindung ist ein -Wert. Als Wert kann der zugrunde liegende Skriptanbieter den Wert nicht verwenden, um die Zuweisung zurück zum Namen auszuführen.
Die BindReference-Methode ähnelt BindValue insofern, als sie auch das Äquivalent von contextObject.name für das angegebene Objekt gemäß einer Reihe von Bindungsregeln ausführt. Das Ergebnis der Bindung dieser Methode ist jedoch ein Verweis anstelle eines Werts. Als Referenz kann der Skriptanbieter den Verweis verwenden, um die Zuweisung zurück zum Namen durchzuführen.
Die EnumerateValues-Methode listet den Satz von Namen und Werten auf, der gemäß den Regeln der BindValue-Methode an das Objekt gebunden wird. Im Gegensatz zu EnumerateKeys, EnumerateValues und ähnlichen Methoden auf IModelObject, die mehrere Namen mit demselben Wert zurückgeben können (für Basisklassen, übergeordnete Modelle usw.), gibt dieser Enumerator nur den spezifischen Satz von Namen zurück, der an BindValue und BindReference gebunden wird. Namen werden nie dupliziert. Beachten Sie, dass die Aufzählung eines Objekts über den Namensbinder erheblich höher ist als der Aufruf der IModelObject-Methoden.
Die EnumerateReferences-Methode listet den Satz von Namen und Verweisen auf sie auf, der gemäß den Regeln der BindReference-Methode an das Objekt gebunden wird. Im Gegensatz zu EnumerateKeys, EnumerateValues und ähnlichen Methoden auf IModelObject, die mehrere Namen mit demselben Wert zurückgeben können (für Basisklassen, übergeordnete Modelle usw.), gibt dieser Enumerator nur den spezifischen Satz von Namen zurück, der an BindValue und BindReference gebunden wird. Namen werden nie dupliziert. Beachten Sie, dass die Aufzählung eines Objekts über den Namensbinder erheblich höher ist als der Aufruf der IModelObject-Methoden.
Debuggerdatenmodell- C++-Skriptdebuggingschnittstellen
Die Infrastruktur für Skriptanbieter im Datenmodell bietet auch ein Konzept zum Debuggen von Skripts. Jedes Skript, das Debugfunktionen für den Debughost und die Debuggeranwendung verfügbar machen möchte, die das Datenmodell hostet, kann dies tun, indem debugfähige Skripts die IDataModelScriptDebug-Schnittstelle zusätzlich zur IDataModelScript-Schnittstelle implementieren. Das Vorhandensein dieser Schnittstelle im Skript gibt der Infrastruktur an, dass sie debuggen kann.
Während die IDataModelScriptDebug-Schnittstelle der Ausgangspunkt ist, um Zugriff auf die Debugfunktionen eines Skriptanbieters zu erhalten, wird sie durch eine Reihe anderer Schnittstellen verknüpft, um allgemeine Debugfunktionen bereitzustellen.
Die Debugschnittstellen sind:
Schnittstelle | Beschreibung |
---|---|
IDataModelScriptDebug | Die Kernschnittstelle, die ein Skriptanbieter bereitstellen muss, um ein Skript debuggen zu können. Die Implementierungsklasse der IDataModelScript-Schnittstelle muss QueryInterface für IDataModelScriptDebug ausführen, wenn das Skript debuggierbar ist. |
IDataModelScriptDebugClient | Die Benutzeroberfläche, die die Möglichkeit des Skriptdebuggens bereitstellen möchte, implementiert die IDataModelScriptDebugClient-Schnittstelle. Der Skriptanbieter verwendet diese Schnittstelle, um Debuginformationen hin und her zu übergeben (z. B. ereignisse, die auftreten, Haltepunkte usw.) |
IDataModelScriptDebugStack | Der Skriptanbieter implementiert diese Schnittstelle, um das Konzept einer Aufrufliste für den Skriptdebugger verfügbar zu machen. |
IDataModelScriptDebugStackFrame | Der Skriptanbieter implementiert diese Schnittstelle, um das Konzept eines bestimmten Stapelrahmens innerhalb der Aufrufliste verfügbar zu machen. |
IDataModelScriptDebugVariableSetEnumerator | Der Skriptanbieter implementiert diese Schnittstelle, um eine Reihe von Variablen verfügbar zu machen. Dieser Satz kann den Satz von Parametern für eine Funktion, den Satz lokaler Variablen oder den Satz von Variablen innerhalb eines bestimmten Bereichs darstellen. Die genaue Bedeutung hängt davon ab, wie die Schnittstelle abgerufen wurde. |
IDataModelScriptDebugBreakpoint | Der Skriptanbieter implementiert diese Schnittstelle, um das Konzept und die Steuerung eines bestimmten Haltepunkts innerhalb des Skripts verfügbar zu machen. |
IDataModelScriptDebugBreakpointEnumerator | Der Skriptanbieter implementiert dies, um alle Haltepunkte aufzulisten, die derzeit im Skript vorhanden sind (ob aktiviert oder nicht). |
Die allgemeinen Verwaltungsschnittstellen sind:
Schnittstelle | Beschreibung |
---|---|
IDataModelScriptProvider | Die Kernschnittstelle, die ein Skriptanbieter implementieren muss. Dies ist die Schnittstelle, die beim Skript-Manager-Teil des Datenmodell-Managers registriert wird, um die Unterstützung eines bestimmten Skripttyps durch den Anbieter anzukündigen und sich für eine bestimmte Dateierweiterung zu registrieren. |
IDataModelScript | Eine Abstraktion eines bestimmten Skripts, das vom Anbieter verwaltet wird. Jedes Skript, das geladen oder bearbeitet wird, verfügt über einen separaten IDataModelScript-instance |
IDataModelScriptClient | Eine Clientschnittstelle, die vom Skriptanbieter verwendet wird, um Informationen an eine Benutzeroberfläche zu übermitteln. Skriptanbieter implementieren diese Schnittstelle nicht. Die Anwendung, die das Datenmodell hosten soll, das Skriptanbieter verwenden möchte, tut dies. Ein Skriptanbieter ruft Methoden des Skriptclients auf, um status, Fehler usw. zu melden. |
IDataModelScriptHostContext | Eine Hostschnittstelle, die vom Skriptanbieter als Container für den Inhalt des Skripts verwendet wird. Wie der Inhalt eines Skripts anders als die Bearbeitungen, die es für das Objektmodell der Debuggeranwendung ausführt, angezeigt wird, hängt vom jeweiligen Debughost ab. Diese Schnittstelle ermöglicht es dem Skriptanbieter, Informationen darüber abzurufen, wo der Inhalt platziert werden soll. |
IDataModelScriptTemplate | Skriptanbieter können eine oder mehrere Vorlagen bereitstellen, die benutzern als Ausgangspunkte zum Erstellen von Skripts dienen. Eine Debuggeranwendung, die einen integrierten Editor bereitstellt, kann neue Skripts mit Vorlageninhalten vorab ausfüllen, wie vom Anbieter über diese Schnittstelle angekündigt. |
IDataModelScriptTemplateEnumerator | Eine Enumeratorschnittstelle, die der Skriptanbieter implementiert, um alle unterstützten Vorlagen anzukündigen. |
IDataModelNameBinder | Eine Namensbindung – ein Objekt, das einen Namen in einem Kontext einem Wert zuordnen kann. Für einen bestimmten Ausdruck, z. B. "foo.bar", kann ein Namensbinder den Namen "bar" im Kontext des Objekts "foo" binden und einen Wert oder einen Verweis darauf erzeugen. Namensbinder werden in der Regel nicht von einem Skriptanbieter implementiert. Stattdessen kann der Standardbinder aus dem Datenmodell abgerufen und vom Skriptanbieter verwendet werden. |
Debuggen von Skripts: IDataModelScriptDebug
Jedes Skript, das debuggierbar ist, gibt diese Funktion über das Vorhandensein der IDataModelScriptDebug-Schnittstelle in derselben Komponente an, die IDataModelScript implementiert. Die Abfrage für diese Schnittstelle durch den Debughost oder die Debuggeranwendung, die das Datenmodell hosten, gibt an, dass die Debugfunktion vorhanden ist.
Die IDataModelScriptDebug-Schnittstelle ist wie folgt definiert.
DECLARE_INTERFACE_(IDataModelScriptDebug, IUnknown)
{
STDMETHOD_(ScriptDebugState, GetDebugState)() PURE;
STDMETHOD(GetCurrentPosition)(_Out_ ScriptDebugPosition *currentPosition, _Out_opt_ ScriptDebugPosition *positionSpanEnd, _Out_opt_ BSTR *lineText) PURE;
STDMETHOD(GetStack)(_COM_Outptr_ IDataModelScriptDebugStack **stack) PURE;
STDMETHOD(SetBreakpoint)(_In_ ULONG linePosition, _In_ ULONG columnPosition, _COM_Outptr_ IDataModelScriptDebugBreakpoint **breakpoint) PURE;
STDMETHOD(FindBreakpointById)(_In_ ULONG64 breakpointId, _COM_Outptr_ IDataModelScriptDebugBreakpoint **breakpoint) PURE;
STDMETHOD(EnumerateBreakpoints)(_COM_Outptr_ IDataModelScriptDebugBreakpointEnumerator **breakpointEnum) PURE;
STDMETHOD(GetEventFilter)(_In_ ScriptDebugEventFilter eventFilter, _Out_ bool *isBreakEnabled) PURE;
STDMETHOD(SetEventFilter)(_In_ ScriptDebugEventFilter eventFilter, _In_ bool isBreakEnabled) PURE;
STDMETHOD(StartDebugging)(_In_ IDataModelScriptDebugClient *debugClient) PURE;
STDMETHOD(StopDebugging)(_In_ IDataModelScriptDebugClient *debugClient) PURE;
}
Die GetDebugState-Methode gibt den aktuellen Status des Skripts zurück (z. B. ob es ausgeführt wird oder nicht). Der Zustand wird durch einen Wert innerhalb der ScriptDebugState-Enumeration definiert.
Die GetCurrentPosition-Methode gibt die aktuelle Position im Skript zurück. Dies kann nur aufgerufen werden, wenn das Skript in den Debugger unterteilt wird, wo ein Aufruf von GetScriptState ScriptDebugBreak zurückgibt. Jeder andere Aufruf dieser Methode ist ungültig und schlägt fehl.
Die GetStack-Methode ruft die aktuelle Aufrufliste an der Unterbrechungsposition ab. Diese Methode kann nur aufgerufen werden, wenn das Skript in den Debugger unterteilt ist.
Die SetBreakpoint-Methode legt einen Haltepunkt innerhalb des Skripts fest. Beachten Sie, dass die Implementierung die inpassierten Zeilen- und Spaltenpositionen so anpassen kann, dass sie zu einer geeigneten Codeposition weitergeleitet werden. Die tatsächlichen Zeilen- und Spaltennummern, in denen der Haltepunkt platziert wurde, können durch Methodenaufrufe auf der zurückgegebenen IDataModelScriptDebugBreakpoint-Schnittstelle abgerufen werden.
Jedem Haltepunkt, der innerhalb des Skripts über die SetBreakpoint-Methode erstellt wird, wird von der Implementierung ein eindeutiger Bezeichner (eine 64-Bit-Ganzzahl ohne Vorzeichen) zugewiesen. Die FindBreakpointById-Methode wird verwendet, um eine Schnittstelle zum Haltepunkt von einem bestimmten Bezeichner abzurufen.
Die EnumerateBreakpoints-Methode gibt einen Enumerator zurück, der jeden Haltepunkt auflisten kann, der innerhalb eines bestimmten Skripts festgelegt ist.
Die GetEventFilter-Methode gibt zurück, ob "break on event" für ein bestimmtes Ereignis aktiviert ist. Ereignisse, die "Ereignisunterbrechung" verursachen können, werden von einem Member der ScriptDebugEventFilter-Enumeration beschrieben.
Die SetEventFilter-Methode ändert das Verhalten "break on event" für ein bestimmtes Ereignis, das von einem Member der ScriptDebugEventFilter-Enumeration definiert wird. Eine vollständige Liste der verfügbaren Ereignisse (und eine Beschreibung dieser Enumeration) finden Sie in der Dokumentation für die GetEventFilter-Methode.
Die StartDebugging-Methode "aktiviert" den Debugger für ein bestimmtes Skript. Das Starten des Debuggens führt nicht aktiv zu Ausführungsunterbrechungen oder Schrittweisen. Es macht das Skript lediglich debugbar und stellt eine Reihe von Schnittstellen für den Client bereit, um mit der Debugschnittstelle zu kommunizieren.
Die StopDebugging-Methode wird von einem Client aufgerufen, der das Debuggen beenden möchte. Dieser Methodenaufruf kann jederzeit erfolgen, nachdem StartDebugging erfolgreich durchgeführt wurde (z. B. während einer Unterbrechung, während das Skript ausgeführt wird usw.). Der Aufruf beendet sofort alle Debugaktivitäten und setzt den Zustand zurück auf, bevor StartDebugging aufgerufen wurde.
Die Debugschnittstelle: IDataModelScriptDebugClient
Der Debughost oder die Debuggeranwendung, die eine Schnittstelle für das Skriptdebuggen bereitstellen möchte, muss eine Implementierung der IDataModelScriptDebugClient-Schnittstelle für den Skriptdebugger über die StartDebugging-Methode auf der Debugschnittstelle für das Skript bereitstellen.
IDataModelScriptDebugClient ist der Kommunikationskanal, über den Debugereignisse übergeben werden und die Steuerung von der Skriptausführungs-Engine zu einer Debuggerschnittstelle wechselt. Sie ist wie folgt definiert.
DECLARE_INTERFACE_(IDataModelScriptDebugClient, IUnknown)
{
STDMETHOD(NotifyDebugEvent)(_In_ ScriptDebugEventInformation *pEventInfo, _In_ IDataModelScript *pScript, _In_opt_ IModelObject *pEventDataObject, _Inout_ ScriptExecutionKind *resumeEventKind) PURE;
}
Wenn ein Ereignis auftritt, das in den Skriptdebugger einbricht, ruft der Debugcode selbst die Schnittstelle über die NotifyDebugEvent-Methode auf. Diese Methode ist synchron. Die Ausführung des Skripts wird erst fortgesetzt, wenn die Schnittstelle vom Ereignis zurückgibt. Die Definition des Skriptdebuggers soll einfach sein: Es gibt absolut keine geschachtelten Ereignisse, die verarbeitet werden müssen. Ein Debugereignis wird durch einen Variantendatensatz definiert, der als ScriptDebugEventInformation bezeichnet wird. Welche Felder in den Ereignisinformationen gültig sind, wird größtenteils durch das DebugEvent-Element definiert. Es definiert die Art des Ereignisses, das wie von einem Member der ScriptDebugEvent-Enumeration beschrieben aufgetreten ist.
Die Aufrufliste: IDataModelScriptDebugStack
Wenn ein Ereignis auftritt, das in den Skriptdebugger einbricht, möchte die Debugschnittstelle die Aufrufliste für den Unterbrechungsort abrufen. Dies erfolgt über die GetStack-Methode. Ein solcher Stapel wird über den IDataModelScriptDebugStack ausgedrückt, der wie unten angegeben definiert ist.
Beachten Sie, dass der Gesamtstapel mehrere Skripts und/oder mehrere Skriptanbieter umfassen kann. Die Aufrufliste, die von einem einzelnen Aufruf der GetStack-Methode auf der Debugschnittstelle eines bestimmten Skripts zurückgegeben wird, sollte nur das Segment der Aufrufliste innerhalb der Grenzen dieses Skripts zurückgeben. Es ist durchaus möglich, dass eine Skriptdebug-Engine die Aufrufliste abrufen kann, da sie mehrere Skriptkontexte umfasst, wenn zwei Skripts desselben Anbieters interagieren. Die GetStack-Methode sollte nicht den Teil des Stapels zurückgeben, der sich in einem anderen Skript befindet. Wenn diese Situation erkannt werden kann, sollte sich der Stapelrahmen, der der Begrenzungsrahmen im Skript ist, über eine Implementierung der Methoden IsTransitionPoint und GetTransition in diesem Stapelrahmen als Übergangsframe markieren. Es wird erwartet, dass die Debuggerschnittstelle den gesamten Stapel aus den vorhandenen mehreren Stapelsegmenten zusammenfügt.
Es ist zwingend erforderlich, dass Übergänge auf diese Weise implementiert werden, oder die Debugschnittstelle kann Abfragen zu lokalen Variablen, Parametern, Haltepunkten und anderen skriptspezifischen Konstrukten in den falschen Skriptkontext leiten! Dies führt zu undefiniertem Verhalten in der Debuggerschnittstelle.
DECLARE_INTERFACE_(IDataModelScriptDebugStack, IUnknown)
{
STDMETHOD_(ULONG64, GetFrameCount)() PURE;
STDMETHOD(GetStackFrame)(_In_ ULONG64 frameNumber, _COM_Outptr_ IDataModelScriptDebugStackFrame **stackFrame) PURE;
}
Die GetFrameCount-Methode gibt die Anzahl der Stapelframes in diesem Segment der Aufrufliste zurück. Wenn der Anbieter Frames in unterschiedlichen Skriptkontexten oder von unterschiedlichen Anbietern erkennen kann, sollte er dies dem Aufrufer durch Implementierung der IsTransitionPoint- und GetTransition-Methoden im Einstiegsrahmen in dieses Stapelsegment mitteilen.
GetStackFrame ruft einen bestimmten Stapelrahmen aus dem Stapelsegment ab. Die Aufrufliste verfügt über ein nullbasiertes Indizierungssystem: Der aktuelle Stapelrahmen, in dem das Unterbrechungsereignis aufgetreten ist, ist Frame 0. Der Aufrufer der aktuellen Methode ist Frame 1 (usw.).
Untersuchen des Zustands bei Defekt: IDataModelScriptDebugStackFrame
Ein bestimmter Frame der Aufrufliste, wenn er in den Skriptdebugger unterteilt wird, kann über einen Aufruf der GetStackFrame-Methode auf der IDataModelScriptDebugStack-Schnittstelle abgerufen werden, die das Stapelsegment darstellt, in dem die Unterbrechung aufgetreten ist. Die IDataModelScriptDebugStackFrame-Schnittstelle, die zurückgegeben wird, um diesen Frame darzustellen, ist wie folgt definiert.
DECLARE_INTERFACE_(IDataModelScriptDebugStackFrame, IUnknown)
{
STDMETHOD(GetName)(_Out_ BSTR *name) PURE;
STDMETHOD(GetPosition)(_Out_ ScriptDebugPosition *position, _Out_opt_ ScriptDebugPosition *positionSpanEnd, _Out_opt_ BSTR *lineText) PURE;
STDMETHOD(IsTransitionPoint)(_Out_ bool *isTransitionPoint) PURE;
STDMETHOD(GetTransition)(_COM_Outptr_ IDataModelScript **transitionScript, _Out_ bool *isTransitionContiguous) PURE;
STDMETHOD(Evaluate)(_In_ PCWSTR pwszExpression, _COM_Outptr_ IModelObject **ppResult) PURE;
STDMETHOD(EnumerateLocals)(_COM_Outptr_ IDataModelScriptDebugVariableSetEnumerator **variablesEnum) PURE;
STDMETHOD(EnumerateArguments)(_COM_Outptr_ IDataModelScriptDebugVariableSetEnumerator **variablesEnum) PURE;
}
Die GetName-Methode gibt den Anzeigenamen (z. B. Funktionsname) dieses Frames zurück. Dieser Name wird innerhalb des Stapelrückverfolgungs angezeigt, der dem Benutzer in der Debuggerschnittstelle angezeigt wird.
Die GetPosition-Methode gibt die Position innerhalb des Skripts zurück, das durch den Stapelrahmen dargestellt wird. Diese Methode kann nur aufgerufen werden, wenn sich das Skript innerhalb eines Durchbruchs befindet, der durch den Stapel dargestellt wird, in dem dieser Frame enthalten ist. Die Zeilen- und Spaltenposition in diesem Frame wird immer zurückgegeben. Wenn der Debugger in der Lage ist, die Spanne der "Ausführungsposition" innerhalb des Skripts zurückzugeben, kann eine Endposition im Argument positionSpanEnd zurückgegeben werden. Wenn der Debugger dazu nicht in der Lage ist, sollten die Zeilen- und Spaltenwerte im Span-Ende (falls angefordert) auf 0 festgelegt werden.
Die IDataModelScriptDebugStack-Schnittstelle stellt ein Segment eines Aufrufstapels dar – den Teil des Aufrufstapels, der im Kontext eines Skripts enthalten ist. Wenn der Debugger den Übergang von einem Skript zu einem anderen (oder von einem Skriptanbieter zu einem anderen) erkennen kann, kann er dies angeben, indem er die IsTransitionPoint-Methode implementiert und je nach Bedarf true oder false zurückgibt. Der Aufrufstapelrahmen, der in das Skript eingegeben hat, in dem das Segment gilt, sollte als Übergangspunkt betrachtet werden. Alle anderen Frames sind nicht.
Wenn ein bestimmter Stapelrahmen ein Von der IsTransition-Methode ermittelter Übergangspunkt ist (eine Definition von Übergangspunkten finden Sie in der Dokumentation), gibt die GetTransition-Methode Informationen zum Übergang zurück. Insbesondere gibt diese Methode das vorherige Skript zurück, das einen Aufruf des Skripts vorgenommen hat, das durch das Stapelsegment dargestellt wird, das diesen IDataModelScriptDebugStackFrame enthält.
Die Evaluate-Methode wertet einen Ausdruck (der Sprache des Skriptanbieters) im Kontext des Stapelrahmens aus, der durch die IDataModelScriptDebugStackFrame-Schnittstelle dargestellt wird, für die diese Methode aufgerufen wurde. Das Ergebnis der Ausdrucksauswertung muss aus dem Skriptanbieter als IModelObject gemarst werden. Die Eigenschaften und anderen Konstrukte für das resultierende IModelObject müssen alle in der Lage sein, abgerufen werden zu können, während sich der Debugger in einem Unterbrechungszustand befindet.
Die EnumerateLocals-Methode gibt einen Variablensatz (dargestellt durch eine IDataModelScriptDebugVariableSetEnumerator-Schnittstelle) für alle lokalen Variablen zurück, die sich im Kontext des Stapelrahmens befinden, der durch die IDataModelScriptDebugStackFrame-Schnittstelle dargestellt wird, für die diese Methode aufgerufen wurde.
Die EnumerateArguments-Methode gibt einen Variablensatz (dargestellt durch eine IDataModelScriptDebugVariableSetEnumerator-Schnittstelle) für alle Funktionsargumente der Funktion zurück, die im Stapelrahmen aufgerufen wird, der durch die IDataModelScriptDebugStackFrame-Schnittstelle dargestellt wird, für die diese Methode aufgerufen wurde.
Betrachten von Variablen: IDataModelScriptDebugVariableSetEnumerator
Eine Gruppe von Variablen im zu debuggenden Skript (ob die variablen in einem bestimmten Bereich, die lokalen Elemente einer Funktion, die Argumente einer Funktion usw.) werden durch einen Variablensatz dargestellt, der über die IDataModelScriptDebugVariableSetEnumerator-Schnittstelle definiert ist:
DECLARE_INTERFACE_(IDataModelScriptDebugVariableSetEnumerator, IUnknown)
{
STDMETHOD(Reset)() PURE;
STDMETHOD(GetNext)(_Out_ BSTR *variableName, _COM_Outptr_opt_ IModelObject **variableValue, _COM_Outptr_opt_result_maybenull_ IKeyStore **variableMetadata) PURE;
}
Die Reset-Methode setzt die Position des Enumerators an der Stelle zurück, an der er sich unmittelbar nach der Erstellung befand, d. h. vor dem ersten Element der Gruppe.
Die GetNext-Methode verschiebt den Enumerator zur nächsten Variablen im Satz und gibt den Namen, den Wert und alle ihr zugeordneten Metadaten zurück. Wenn der Enumerator das Ende des Satzes erreicht hat, wird der Fehler E_BOUNDS zurückgegeben. Nachdem der E_BOUNDS Marker von der GetNext-Methode zurückgegeben wurde, erzeugt er weiterhin E_BOUNDS, wenn er erneut aufgerufen wird, es sei denn, es wird ein dazwischenliegender Reset-Aufruf ausgeführt.
Haltepunkte: IDataModelScriptDebugBreakpoint
Skript breakpoints werden über die SetBreakpoint-Methode auf der Debugschnittstelle eines bestimmten Skripts festgelegt. Solche Haltepunkte werden sowohl durch eine eindeutige ID als auch durch eine Implementierung der IDataModelScriptDebugBreakpoint-Schnittstelle dargestellt, die wie folgt definiert wird.
DECLARE_INTERFACE_(IDataModelScriptDebugBreakpoint, IUnknown)
{
STDMETHOD_(ULONG64, GetId)() PURE;
STDMETHOD_(bool, IsEnabled)() PURE;
STDMETHOD_(void, Enable)() PURE;
STDMETHOD_(void, Disable)() PURE;
STDMETHOD_(void, Remove)() PURE;
STDMETHOD(GetPosition)(_Out_ ScriptDebugPosition *position, _Out_opt_ ScriptDebugPosition *positionSpanEnd, _Out_opt_ BSTR *lineText) PURE;
}
Die GetId-Methode gibt den eindeutigen Bezeichner zurück, der vom Debugmodul des Skriptanbieters dem Haltepunkt zugewiesen wurde. Dieser Bezeichner muss innerhalb des Kontexts des enthaltenden Skripts eindeutig sein. Der Haltepunktbezeichner kann für den Anbieter eindeutig sein. dies ist jedoch nicht erforderlich.
Die IsEnabled-Methode gibt zurück, ob der Haltepunkt aktiviert ist oder nicht. Ein deaktivierter Haltepunkt ist weiterhin vorhanden und befindet sich weiterhin in der Liste der Haltepunkte für das Skript, er wird nur vorübergehend "deaktiviert". Alle Haltepunkte sollten im aktivierten Zustand erstellt werden.
Die Enable-Methode aktiviert den Haltepunkt. Wenn der Haltepunkt deaktiviert wurde, führt das "Erreichen des Haltepunkts" nach dem Aufrufen dieser Methode zu einer Unterbrechung des Debuggers.
Die Disable-Methode deaktiviert den Haltepunkt. Nach diesem Aufruf wird das "Erreichen des Haltepunkts" nach dem Aufrufen dieser Methode nicht in den Debugger unterteilt. Der Haltepunkt gilt, obwohl er noch vorhanden ist, als "deaktiviert".
Die Remove-Methode entfernt den Haltepunkt aus der enthaltenden Liste. Der Haltepunkt ist nach der Rückgabe dieser Methode semantisch nicht mehr vorhanden. Die IDataModelScriptDebugBreakpoint-Schnittstelle, die den Haltepunkt darstellt, gilt nach dem Aufruf als verwaist. Nach diesem Aufruf kann (rechtlich) nichts anderes getan werden, als es freizugeben.
Die GetPosition-Methode gibt die Position des Haltepunkts im Skript zurück. Der Skriptdebugger muss die Zeile und Spalte im Quellcode zurückgeben, an der sich der Haltepunkt befindet. Wenn dies möglich ist, kann sie auch eine Durch den Haltepunkt dargestellte Quellspanne zurückgeben, indem eine Endposition ausgefüllt wird, die durch das Argument positionSpanEnd definiert wird. Wenn der Debugger nicht in der Lage ist, diese Spanne zu erzeugen und der Aufrufer sie anfordert, sollten die Felder Zeile und Spalte der Endposition der Spanne als null ausgefüllt werden, was angibt, dass die Werte nicht angegeben werden können.
Breakpoint-Enumeration: IDataModelScriptDebugBreakpointEnumerator
Wenn ein Skriptanbieter das Debuggen unterstützt, muss er auch alle Haltepunkte nachverfolgen, die jedem einzelnen Skript zugeordnet sind, und in der Lage sein, diese Haltepunkte in der Debugschnittstelle aufzulisten. Der Enumerator für Haltepunkte wird über die EnumerateBreakpoints-Methode auf der Debugschnittstelle für ein bestimmtes Skript abgerufen und wie folgt definiert.
DECLARE_INTERFACE_(IDataModelScriptDebugBreakpointEnumerator, IUnknown)
{
STDMETHOD(Reset)() PURE;
STDMETHOD(GetNext)(_COM_Outptr_ IDataModelScriptDebugBreakpoint **breakpoint) PURE;
}
Die Reset-Methode setzt die Position des Enumerators auf die Position zurück, an der er sich direkt nach der Erstellung des Enumerators befand , d. h. vor dem ersten aufgezählten Haltepunkt.
Die GetNext-Methode verschiebt den Enumerator zum nächsten Breakpoint, der aufgelistet werden soll, und gibt die IDataModelScriptDebugBreakpoint-Schnittstelle für diesen Haltepunkt zurück. Wenn der Enumerator das Ende der Enumeration erreicht hat, gibt er E_BOUNDS zurück. Nachdem der E_BOUNDS Fehler erzeugt wurde, werden nachfolgende Aufrufe der GetNext-Methode weiterhin E_BOUNDS erzeugen, es sei denn, es wurde ein eingreifender Aufruf der Reset-Methode ausgeführt.
Siehe auch
Dieses Thema ist Teil einer Reihe, in der die Schnittstellen beschrieben werden, auf die über C++ zugegriffen werden kann, wie sie zum Erstellen einer C++-basierten Debuggererweiterung verwendet werden und wie andere Datenmodellkonstrukte (z. B. JavaScript oder NatVis) aus einer C++-Datenmodellerweiterung verwendet werden.
Debuggerdatenmodell C++-Übersicht
Debuggerdatenmodell-C++-Schnittstellen
Debuggerdatenmodell C++-Objekte