偵錯工具資料模型 C++ 腳本
本主題描述如何使用偵錯工具資料模型 C++ 偵錯工具資料模型 C++ 腳本來支援使用腳本的偵錯工具引擎自動化。
偵錯工具資料模型中的腳本管理
除了資料模型管理員的角色作為物件建立和擴充性的中央授權單位之外,它也會負責管理腳本的抽象概念。 從資料模型管理員的腳本管理員部分的觀點來看,腳本是可以動態載入、卸載和可能由提供者偵錯的專案,以便擴充或提供新功能給資料模型。
腳本提供者是一個元件,可橋接語言 (,例如:NatVis、JavaScript 等...) 至資料模型。 它會 (註冊一或多個副檔名,例如:「。由提供者處理的 NatVis「、」.js「) ,允許偵錯工具用戶端或使用者介面透過委派給提供者,以允許載入具有該特定副檔名的腳本檔案。
核心腳本管理員:IDataModelScriptManager
核心腳本管理員介面的定義如下。
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;
}
GetDefaultNameBinder 方法會傳回資料模型的預設腳本名稱系結器。 名稱系結器是解析物件內容中名稱的元件。 例如,假設運算式 「foo.bar」,系統會呼叫名稱系結器來解析物件 foo 內容中的名稱列。 此處傳回的系結器會遵循一組資料模型的預設規則。 腳本提供者可以使用這個系結器,在提供者間提供名稱解析的一致性。
RegisterScriptProvider 方法會通知資料模型,新的腳本提供者存在,其能夠將新語言橋接至資料模型。 呼叫這個方法時,腳本管理員會立即回呼指定的腳本提供者,並查詢所管理之腳本的屬性。 如果已在指定腳本提供者所指出的名稱或副檔名下註冊提供者,這個方法將會失敗。 只有單一腳本提供者可以註冊為特定名稱或副檔名的處理常式。
UnregisterScriptProvider 方法會復原 RegisterScriptProvider 方法的呼叫。 Inpassed 腳本提供者所提供的名稱和副檔名將不再與其相關聯。 請務必注意,即使取消註冊之後,腳本提供者仍有大量的未處理 COM 參考。 這個方法只會防止載入/建立指定腳本提供者所管理的型別腳本。 如果該提供者所載入的腳本仍然載入,或已操作偵錯工具的物件模型 (或資料模型) ,這些操作可能仍會參考回腳本。 腳本中可能有直接參考建構的資料模型、方法或物件。 腳本提供者必須準備好處理。
FindProviderForScriptType 方法會在腳本管理員中搜尋具有腳本類型字串的提供者,如此方法所示。 如果找不到此方法,此方法將會失敗;否則,這類腳本提供者會傳回給呼叫端。
EnumerateScriptProviders 方法會傳回列舉值,它會列舉已透過 RegisterScriptProvider 方法呼叫之前向腳本管理員註冊的每個腳本提供者。
腳本提供者列舉:IDataModelScriptProviderEnumerator
EnumerateScriptProviders 方法會傳回下列形式的列舉值:
DECLARE_INTERFACE_(IDataModelScriptProviderEnumerator, IUnknown)
{
STDMETHOD(Reset)() PURE;
STDMETHOD(GetNext)(_COM_Outptr_ IDataModelScriptProvider **provider) PURE;
}
Reset 方法會將枚舉器移至傳回第一個專案之前的位置。
GetNext 方法會將列舉值向前移動一個專案,並傳回位於該專案的腳本提供者。 當列舉值到達列舉的結尾時,將會傳回E_BOUNDS。 在收到此錯誤之後呼叫 GetNext 方法會繼續無限期地傳回E_BOUNDS。
用於腳本的偵錯工具資料模型 C++ 主機介面
主機在腳本中的角色
偵錯主機會公開一系列非常低層級的介面,以瞭解其偵錯目標型別系統的本質 () 、評估其偵錯目的語言中的運算式 (s) 等等...一般而言,它不會受到較高層級建構的考慮,例如腳本。 這類功能會保留給整體偵錯工具應用程式或提供這些功能的擴充功能。 不過,這是例外狀況。 任何想要參與資料模型所提供之整體腳本體驗的偵錯主機,都必須實作幾個簡單的介面,以提供內容給腳本。 實際上,偵錯主機可控制其想要讓腳本環境將函式和其他腳本提供的功能放在資料模型的命名空間內。 參與此程式可讓主機允許 (或不) 使用這類函式,例如其運算式評估工具。 從主機的觀點來看,這些介面包括:
介面 | 描述 |
---|---|
IDebugHostScriptHost | 介面,表示偵錯主機在腳本環境中加入的功能。 此介面可讓您建立內容,以通知腳本引擎放置物件的位置。 |
IDataModelScriptHostCoNtext | 腳本提供者用來作為腳本內容的容器的主機介面。 除了對偵錯工具應用程式物件模型執行之操作以外的指令碼介面內容,如何由特定的偵錯主機決定。 此介面可讓腳本提供者取得放置其內容位置的相關資訊。 如需詳細資訊,請參閱本主題稍後的資料 模型 C++ 指令碼介面 。 |
偵錯主機的腳本主機:IDebugHostScriptHost
IDebugHostScriptHost 介面是腳本提供者用來從偵錯主機取得新建立腳本內容的介面。 此內容包含偵錯主機所提供的物件 (,) 腳本提供者可以在資料模型與腳本環境之間放置任何橋接器。 例如,這類橋接器可能是叫用腳本函式的資料模型方法。 這樣做可讓資料模型端的呼叫端利用 IModelMethod 介面上的 Call 方法叫用腳本方法。
IDebugHostScriptHost 介面的定義如下。
DECLARE_INTERFACE_(IDebugHostScriptHost, IUnknown)
{
STDMETHOD(CreateContext)(_In_ IDataModelScript* script, _COM_Outptr_ IDataModelScriptHostContext** scriptContext) PURE;
}
CreateCoNtext 方法是由腳本提供者呼叫,以建立要放置腳本內容的新內容。 這類內容是由資料模型 C++ 指令碼介面頁面上詳細說明的 IDataModelScriptHostCoNtext 介面來表示。
偵錯工具資料模型 C++ 指令碼介面
腳本和指令碼介面
資料模型的整體架構可讓協力廠商定義某些語言與資料模型物件模型之間的橋樑。 一般而言,所橋接的語言是指令碼語言,因為資料模型的環境非常動態。 定義及實作資料模型之語言與物件模型之間的這個橋接器的元件稱為腳本提供者。 初始化時,腳本提供者會向資料模型管理員的腳本管理員部分,以及管理擴充性的任何介面,後續允許編輯、載入、卸載及可能偵錯寫入腳本提供者所管理語言的腳本。
請注意,適用于 Windows 的偵錯工具目前定義了兩個腳本提供者。
- NatVis 提供者。 此提供者內嵌在 NatVis XML 和資料模型之間的DbgEng.dll和橋接器內,允許原生/語言資料類型的視覺效果。
- JavaScript 提供者。 此提供者包含在舊版偵錯工具延伸模組中:JsProvider.dll。 它會橋接以 JavaScript 語言和資料模型撰寫的腳本,允許任意形式的偵錯工具控制和擴充性。
您可以撰寫新的提供者來橋接其他語言 (例如:Python 等...) 資料模型。 這類功能目前會封裝在舊版偵錯工具延伸模組中,以供載入之用。 腳本提供者本身應該將舊版引擎介面的相依性降到最低,而且應該只盡可能利用資料模型 API。 這可讓提供者更容易移植到其他環境。
腳本提供者有兩種介面類別別。 介面的第一類是用於一般管理腳本提供者及其管理的腳本。 第二個介面類別別是支援腳本偵錯。 雖然第一個集合的支援是必要的,但第二個集合的支援是選擇性的,而且對每個提供者都可能沒有意義。
一般管理介面包括:
介面 | 描述 |
---|---|
IDataModelScriptProvider | 腳本提供者必須實作的核心介面。 這是向資料模型管理員的腳本管理員部分註冊的介面,以便公告提供者對特定類型腳本的支援,並針對特定副檔名註冊 |
IDataModelScript | 提供者所管理之特定腳本的抽象概念。 載入或編輯的每個腳本都有個別的 IDataModelScript 實例 |
IDataModelScriptClient | 腳本提供者用來與使用者介面通訊資訊的用戶端介面。 腳本提供者不會實作這個介面。 裝載想要使用腳本提供者之資料模型的應用程式。 腳本提供者會呼叫腳本用戶端的方法,以報告狀態、錯誤等... |
IDataModelScriptHostCoNtext | 腳本提供者用來作為腳本內容的容器的主機介面。 指令碼介面的內容,而不是它對偵錯工具應用程式物件模型執行之操作的內容,如何由特定的偵錯主機決定。 此介面可讓腳本提供者取得放置其內容位置的相關資訊。 |
IDataModelScriptTemplate | 腳本提供者可以提供一或多個範本,做為使用者撰寫腳本的起點。 提供內建編輯器的偵錯工具應用程式可以使用提供者透過這個介面公告的範本內容預先填入新的腳本。 |
IDataModelScriptTemplateEnumerator | 腳本提供者實作的列舉值介面,以公告它支援的所有範本。 |
IDataModelNameBinder | 名稱系結器 -- 物件,可將內容中的名稱與值產生關聯。 對於 「foo.bar」 之類的指定運算式,名稱系結器可以在物件 「foo」 的內容中系結名稱 「bar」,並產生值或參考。 名稱系結器通常不會由腳本提供者實作;相反地,您可以從資料模型取得預設系結器,並由腳本提供者使用 |
偵錯介面如下:
介面 | 描述 |
---|---|
IDataModelScriptDebug | 腳本提供者必須提供的核心介面,才能進行腳本偵錯。 如果腳本可偵錯,IDataModelScript 介面的實作類別必須 QueryInterface for IDataModelScriptDebug。 |
IDataModelScriptDebugClient | 想要提供腳本偵錯功能的使用者介面會實作 IDataModelScriptDebugClient 介面。 腳本提供者會利用這個介面來回傳遞偵錯資訊 (例如:發生的事件、中斷點等等...) |
IDataModelScriptDebugStack | 腳本提供者會實作這個介面,以將呼叫堆疊的概念公開給腳本偵錯工具。 |
IDataModelScriptDebugStackFrame | 腳本提供者會實作這個介面,以公開呼叫堆疊內特定堆疊框架的概念。 |
IDataModelScriptDebugVariableSetEnumerator | 腳本提供者會實作這個介面來公開一組變數。 此集合可能會代表函式的參數集、區域變數集,或特定範圍內的變數集。 確切的意義取決於取得介面的方式。 |
IDataModelScriptDebugBreakpoint | 腳本提供者會實作這個介面,以公開腳本內特定中斷點的概念和控制。 |
IDataModelScriptDebugBreakpointEnumerator | 腳本提供者會實作此動作,以列舉目前存在於腳本中的所有中斷點, (是否啟用) 。 |
核心腳本提供者:IDataModelScriptProvider
任何想要成為腳本提供者的延伸模組都必須提供 IDataModelScriptProvider 介面的實作,並透過 RegisterScriptProvider 方法向資料模型管理員的腳本管理員部分進行註冊。 必須實作的這個核心介面定義如下。
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;
}
GetName 方法會傳回提供者透過 SysAllocString 方法配置的字串所管理之 (或語言) 腳本類型的名稱。 呼叫端負責透過 SysFreeString 釋放傳回的字串。 可能從此方法傳回的字串範例為 「JavaScript」 或 「NatVis」。 傳回的字串可能會出現在裝載資料模型的偵錯工具應用程式使用者介面中。 沒有任何兩個腳本提供者傳回相同名稱, (不區分大小寫的) 。
GetExtension 方法會傳回此提供者所管理的腳本副檔名, (沒有點) 做為透過 SysAllocString 方法配置的字串。 裝載資料模型 (的偵錯工具應用程式與腳本支援) 會將開啟具有此延伸模組的腳本檔案委派給腳本提供者。 呼叫端負責透過 SysFreeString 釋放傳回的字串。 可能從此方法傳回的字串範例為 「js」 或 「NatVis」。
會呼叫 CreateScript 方法來建立新的腳本。 每當呼叫此方法時,腳本提供者必須傳回由傳回的 IDataModelScript 介面所代表的新和空白腳本。 請注意,不論使用者介面是建立新的空白腳本以供使用者編輯,還是偵錯工具應用程式正在從磁片載入腳本,都會呼叫此方法。 提供者不會參與檔案 I/O。 它只會透過傳遞至 IDataModelScript 上方法的資料流程來處理來自主控應用程式的要求。
GetDefaultTemplateContent 方法會傳回提供者預設範本內容的介面。 這是腳本提供者想要在新建立腳本的編輯視窗中預先填入的內容。 如果腳本提供者沒有範本 (或沒有指定為預設內容的範本內容) ,腳本提供者可能會從此方法傳回E_NOTIMPL。
EnumerateTemplates 方法會傳回列舉值,其能夠列舉腳本提供者所提供的各種範本。 範本內容是建立新腳本時,腳本提供者想要「預先填入」到編輯視窗中的內容。 如果支援多個不同的範本,這些範本可以命名 (例如:「命令式腳本」、「延伸模組腳本」) ,而裝載資料模型的偵錯工具應用程式可以選擇如何向使用者呈現「範本」。
核心指令碼介面:IDataModelScript
管理提供者所實作之個別腳本的主要介面是 IDataModelScript 介面。 當用戶端想要建立新的空白腳本,並在 IDataModelScriptProvider 上呼叫 CreateScript 方法時,會傳回實作此介面的元件。
提供者所建立的每個腳本都應該位於獨立定址接收器中。 一個腳本不應該影響另一個腳本,但透過資料模型與外部物件的明確互動除外。 例如,兩個腳本可以擴充某些類型或概念 (例如:偵錯工具對進程) 的概念。 然後,任一腳本都可以透過外部進程物件來存取彼此的欄位。
介面的定義如下。
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;
}
GetName 方法會透過 SysAllocString 函式傳回腳本的名稱做為配置的字串。 如果腳本還沒有名稱,方法應該會傳回 Null BSTR。 在此情況下,它不應該失敗。 如果腳本是透過對 Rename 方法的呼叫明確重新命名,GetName 方法應該會傳回新指派的名稱。
Rename 方法會將新名稱指派給腳本。 腳本實作的責任是儲存此名稱,並在對 GetName 方法的任何呼叫時傳回它。 當使用者介面選擇將腳本儲存為新名稱時,通常會呼叫這個名稱。 請注意,重新命名腳本可能會影響裝載應用程式選擇投影腳本內容的位置。
填入方法是由用戶端呼叫,以變更或同步處理腳本的「內容」。 這是對腳本提供者所做的通知,腳本的程式碼已變更。 請務必注意,此方法不會對腳本操作的任何物件造成腳本執行或變更。 這只是腳本提供者的通知,腳本的內容已變更,以便它可以同步處理自己的內部狀態。
Execute 方法會執行腳本的內容,如上次成功填入呼叫所指示,並根據該內容修改偵錯工具的物件模型。 如果語言 (或腳本提供者) 定義 「main 函式」 -- 作者在使用者介面中按一下虛構的 [執行腳本] 按鈕時呼叫的函式,則不會在執行作業期間呼叫這類「主要函式」。 「執行」作業可以視為只執行初始化和物件模型操作 (例如:執行根程式碼並設定擴充點) 。
Unlink 方法會復原 Execute 作業。 在執行腳本期間所建立的任何物件模型操作或擴充點,都是復原的。 在取消連結作業之後,腳本可以透過呼叫 Execute 重新執行,或可以釋出。
IsInvocable 方法會傳回腳本是否可叫用 ,也就是說,它是否有其語言或提供者所定義的「主要函式」。 這類「主要函式」在概念上是腳本作者在使用者介面中按下虛構的 「執行腳本」按鈕時所要呼叫的內容。
如果腳本具有「main 函式」,其旨在從 UI 調用執行,它會透過 IsInvocable 方法的 true 傳回來表示這類函式。 然後,使用者介面可以呼叫 InvokeMain 方法,以實際「叫用」腳本。 請注意,這與 Execute 不同,它會執行所有根程式碼,並將腳本橋接至基礎主機的命名空間。
**腳本用戶端:IDataModelScriptClient **
裝載想要管理腳本並擁有使用者介面的應用程式, (不論圖形化還是主控台) 有關此概念的應用程式,都會實作 IDataModelScriptClient 介面。 此介面會在執行或叫用或腳本期間傳遞至任何腳本提供者,以便將錯誤和事件資訊傳回給使用者介面。
IDataModelScriptClient 介面的定義如下。
DECLARE_INTERFACE_(IDataModelScriptClient, IUnknown)
{
STDMETHOD(ReportError)(_In_ ErrorClass errClass, _In_ HRESULT hrFail, _In_opt_ PCWSTR message, _In_ ULONG line, _In_ ULONG position) PURE;
}
如果在腳本執行或叫用期間發生錯誤,腳本提供者會呼叫 ReportError 方法,以通知使用者介面發生錯誤。
腳本的主機內容:IDataModelScriptHostCoNtext
偵錯主機對專案資料模型腳本內容的方式和位置有一些影響。 預期每個腳本都會要求主機輸入內容,以便將橋接器放在腳本 (例如:可以呼叫的函式物件等等...) 。透過在 IDebugHostScriptHost 上呼叫 CreateCoNtext 方法並取得 IDataModelScriptHostCoNtext 來擷取此內容。
IDataModelScriptHostCoNtext 介面的定義如下。
DECLARE_INTERFACE_(IDataModelScriptHostContext, IUnknown)
{
STDMETHOD(NotifyScriptChange)(_In_ IDataModelScript* script, _In_ ScriptChangeKind changeKind) PURE;
STDMETHOD(GetNamespaceObject)(_COM_Outptr_ IModelObject** namespaceObject) PURE;
}
腳本提供者必須在發生特定作業時,于相關聯內容上呼叫 NotifyScriptChange 方法時通知偵錯主機。 這類作業會定義為 ScriptChangeKind 列舉的成員
GetNamespaceObject 方法會傳回物件,腳本提供者可以在資料模型與腳本之間放置任何橋接器。 例如,腳本提供者可能會將資料模型方法物件放在 IModelObject (IModelMethod 介面方塊中,) 其實作呼叫腳本中對應的具名函式。
新建立腳本的範本:IDataModelScriptTemplate
想要為新腳本呈現預先填入內容的腳本提供者 (,例如:協助使用者在偵錯工具使用者介面中撰寫腳本,) 藉由提供一或多個腳本範本來執行此動作。 這類範本是實作 IDataModelScriptTemplate 介面的元件,會透過腳本提供者上的 GetDefaultTemplate 方法或 EnumerateTemplates 方法傳回。
IDataModelScriptTemplate 介面的定義如下。
DECLARE_INTERFACE_(IDataModelScriptTemplate, IUnknown)
{
STDMETHOD(GetName)(_Out_ BSTR *templateName) PURE;
STDMETHOD(GetDescription)(_Out_ BSTR *templateDescription) PURE;
STDMETHOD(GetContent)(_COM_Outptr_ IStream **contentStream) PURE;
}
GetName 方法會傳回範本的名稱。 如果範本沒有名稱,這可能會因為E_NOTIMPL而失敗。 如果這類存在, (單一預設範本) 不需要具有名稱。 所有其他範本都是 。 這些名稱可能會在使用者介面中呈現為功能表的一部分,以選取要建立的範本。
GetDescription 方法會傳回範本的描述。 這類描述會在更具描述性的介面中向使用者呈現,以協助使用者瞭解範本的設計目的。 如果這個方法沒有描述,範本可能會傳回E_NOTIMPL。
GetContent 方法會傳回範本的內容 (或程式碼) 。 如果使用者選擇從此範本建立新的腳本,這會預先填入編輯視窗。 範本負責建立 (,並透過用戶端可以提取的內容傳回標準資料流程) 。
提供者範本內容的列舉:IDataModelScriptTemplateEnumerator
腳本提供者可以提供一或多個範本,這些範本會在某些使用者介面中預先填入新建立的腳本。 如果提供上述任何範本,腳本提供者就必須在列舉值上實作列舉值,其會在呼叫 EnumerateTemplates 方法時傳回。
這類列舉值是 IDataModelScriptTemplateEnumerator 介面的實作,並定義如下。
DECLARE_INTERFACE_(IDataModelScriptTemplateEnumerator, IUnknown)
{
STDMETHOD(Reset)() PURE;
STDMETHOD(GetNext)(_COM_Outptr_ IDataModelScriptTemplate **templateContent) PURE;
}
Reset 方法會將列舉值重設為第一次建立時所在的位置-- 在第一個範本產生之前。
GetNext 方法會將列舉值移至下一個範本,並傳回它。 在列舉結束時,列舉值會傳回E_BOUNDS。 一旦叫用E_BOUNDS標記,列舉值就會無限期地產生E_BOUNDS錯誤,直到進行重設呼叫為止。
解析名稱的意義:IDataModelNameBinder
資料模型提供標準方式,讓腳本提供者判斷指定內容中指定名稱的意義 (例如:判斷將跨各種腳本提供者運作之 foo.bar) 的橫條意義。 此機制稱為名稱系結器,並以 IDataModelNameBinder 介面表示。 這類系結器會封裝一組規則,說明名稱解析的方式,以及如何處理在物件上定義多次名稱的衝突解析。 這些規則的一部分包括一些事項,例如資料模型所新增的投影名稱 (一) 會根據所偵錯語言類型系統中的原生名稱 (解析) 。
為了提供跨腳本提供者的一致性程度,資料模型的腳本管理員會提供預設名稱系結器。 您可以透過呼叫 IDataModelScriptManager 介面上的 GetDefaultNameBinder 方法來取得這個預設名稱系結器。 名稱系結器介面的定義如下。
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;
}
BindValue 方法會根據一組系結規則,在指定的 物件上執行對等的 coNtextObject.name。 這個系結的結果是值。 作為值,基礎腳本提供者無法使用 值,將指派傳回給名稱。
BindReference 方法類似于 BindValue,因為它也會根據一組系結規則,在指定的 物件上執行對等的 coNtextObject.name。 不過,這個方法的系結結果是參考,而不是值。 作為參考,腳本提供者可以利用參考來執行指派回名稱。
EnumerateValues 方法會列舉一組名稱和值,這些名稱和值會根據 BindValue 方法的規則來系結至物件。 不同于 IModelObject 上的 EnumerateKeys、EnumerateValues 和類似方法,這些方法可能會針對基類、父模型和類似) 傳回多個具有相同值的名稱 (,此列舉值只會傳回與 BindValue 和 BindReference 系結的特定名稱集。 名稱永遠不會重複。 請注意,透過名稱系結器列舉物件的成本明顯高於呼叫 IModelObject 方法的成本。
EnumerateReferences 方法會列舉一組名稱和參考,這些名稱會根據 BindReference 方法的規則,針對物件系結。 不同于 IModelObject 上的 EnumerateKeys、EnumerateValues 和類似方法,這些方法可能會針對基類、父模型和類似) 傳回多個具有相同值的名稱 (,此列舉值只會傳回與 BindValue 和 BindReference 系結的特定名稱集。 名稱永遠不會重複。 請注意,透過名稱系結器列舉物件的成本明顯高於呼叫 IModelObject 方法的成本。
偵錯工具資料模型 C++ 腳本偵錯介面
資料模型中腳本提供者的基礎結構也提供偵錯腳本的概念。 任何想要對偵錯主機公開偵錯功能的腳本,以及裝載資料模型的偵錯工具應用程式,除了 IDataModelScript 介面之外,還可以讓可偵錯的腳本實作 IDataModelScriptDebug 介面。 腳本上存在此介面,表示其可偵錯的基礎結構。
雖然 IDataModelScriptDebug 介面是存取腳本提供者偵錯功能的起點,但它是由一組其他介面聯結,以提供整體偵錯功能。
偵錯介面包括:
介面 | 描述 |
---|---|
IDataModelScriptDebug | 腳本提供者必須提供的核心介面,才能進行腳本偵錯。 如果腳本可偵錯,IDataModelScript 介面的實作類別就必須查詢 IDataModelScriptDebug 的 QueryInterface。 |
IDataModelScriptDebugClient | 想要提供腳本偵錯功能的使用者介面會實作 IDataModelScriptDebugClient 介面。 腳本提供者會利用此介面來來回傳遞偵錯資訊 (,例如:發生的事件、中斷點等...) |
IDataModelScriptDebugStack | 腳本提供者會實作這個介面,以將呼叫堆疊的概念公開給腳本偵錯工具。 |
IDataModelScriptDebugStackFrame | 腳本提供者會實作這個介面,以公開呼叫堆疊內特定堆疊框架的概念。 |
IDataModelScriptDebugVariableSetEnumerator | 腳本提供者會實作這個介面來公開一組變數。 此集合可能代表函式的參數集、區域變數集,或特定範圍內的變數集合。 確切的意義取決於取得介面的方式。 |
IDataModelScriptDebugBreakpoint | 腳本提供者會實作這個介面,以公開腳本內特定中斷點的概念和控制。 |
IDataModelScriptDebugBreakpointEnumerator | 腳本提供者會實作此動作,以列舉目前存在於腳本中的所有中斷點, (是否啟用) 。 |
一般管理介面如下:
介面 | 描述 |
---|---|
IDataModelScriptProvider | 腳本提供者必須實作的核心介面。 這是向資料模型管理員的腳本管理員部分註冊的介面,以便公告提供者對特定類型腳本的支援,並針對特定副檔名註冊 |
IDataModelScript | 由提供者管理的特定腳本抽象概念。 載入或編輯的每個腳本都有個別的 IDataModelScript 實例 |
IDataModelScriptClient | 腳本提供者用來與使用者介面通訊資訊的用戶端介面。 腳本提供者不會實作這個介面。 裝載想要使用腳本提供者之資料模型的應用程式。 腳本提供者會呼叫腳本用戶端的方法,以報告狀態、錯誤等... |
IDataModelScriptHostCoNtext | 腳本提供者用來作為腳本內容的容器的主機介面。 指令碼介面的內容,而不是它對偵錯工具應用程式物件模型執行之操作的內容,如何由特定的偵錯主機決定。 此介面可讓腳本提供者取得放置其內容位置的相關資訊。 |
IDataModelScriptTemplate | 腳本提供者可以提供一或多個範本,做為使用者撰寫腳本的起點。 提供內建編輯器的偵錯工具應用程式可以使用提供者透過這個介面公告的範本內容預先填入新的腳本。 |
IDataModelScriptTemplateEnumerator | 腳本提供者實作的列舉值介面,以公告它支援的所有範本。 |
IDataModelNameBinder | 名稱系結器 -- 物件,可將內容中的名稱與值產生關聯。 對於 「foo.bar」 之類的指定運算式,名稱系結器可以在物件 「foo」 的內容中系結名稱 「bar」,並產生值或參考。 名稱系結器通常不會由腳本提供者實作;相反地,您可以從資料模型取得預設系結器,並由腳本提供者使用。 |
讓腳本偵錯:IDataModelScriptDebug
任何可偵錯的腳本會透過實作 IDataModelScriptScript 之相同元件上的 IDataModelScriptDebug 介面來指出這項功能。 偵錯主機或裝載資料模型的偵錯工具應用程式會查詢此介面,即表示偵錯功能是否存在。
IDataModelScriptDebug 介面的定義如下。
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;
}
GetDebugState 方法會傳回腳本的目前狀態 (例如:它是否正在執行) 。 狀態是由 ScriptDebugState 列舉內的值所定義。
GetCurrentPosition' 方法會傳回腳本內的目前位置。 只有當腳本中斷至偵錯工具時,才能呼叫 GetScriptState 會傳回 ScriptDebugBreak。 對這個方法的任何其他呼叫都無效,而且將會失敗。
GetStack 方法會在中斷位置取得目前的呼叫堆疊。 只有在腳本中斷至偵錯工具時,才能呼叫這個方法。
SetBreakpoint 方法會在腳本內設定中斷點。 請注意,實作可以自由調整內嵌行和資料行位置,以向前移至適當的程式碼位置。 在傳回的 IDataModelScriptDebugBreakpoint 介面上,方法呼叫可以擷取中斷點的實際行號和資料行編號。
透過 SetBreakpoint 方法在腳本內建立的每個中斷點都會指派唯一識別碼, (實作) 64 位不帶正負號的整數。 FindBreakpointById 方法可用來從指定的識別碼取得中斷點的介面。
EnumerateBreakpoints 方法會傳回列舉值,其能夠列舉特定腳本內設定的每個中斷點。
GetEventFilter 方法會傳回是否針對特定事件啟用「中斷事件」。 ScriptDebugEventFilter 列舉的成員會描述可能造成「事件中斷」的事件。
SetEventFilter 方法會變更 ScriptDebugEventFilter 列舉成員所定義之特定事件的「事件中斷」行為。 如需可用事件的完整清單 (,以及此列舉) 的說明,請參閱 GetEventFilter 方法的檔。
StartDebugging 方法會「開啟」特定腳本的偵錯工具。 啟動偵錯的動作不會主動造成任何執行中斷或逐步執行。 它只會讓腳本可偵錯,並提供一組介面供用戶端與偵錯介面通訊。
StopDebugging 方法是由想要停止偵錯的用戶端所呼叫。 這個方法呼叫可能會在 StartDebugging 成功 (之後的任何時間點進行,例如:在中斷期間、腳本正在執行等...) 。呼叫會立即停止所有偵錯活動,並在呼叫 StartDebugging 之前將狀態重設為 。
偵錯介面:IDataModelScriptDebugClient
想要在腳本偵錯周圍提供介面的偵錯主機或偵錯工具應用程式,必須透過腳本偵錯介面上的 StartDebugging 方法,將 IDataModelScriptDebugClient 介面實作提供給腳本偵錯工具。
IDataModelScriptDebugClient 是傳遞偵錯事件的通道,而控制權會從腳本執行引擎移至偵錯工具介面。 其定義如下。
DECLARE_INTERFACE_(IDataModelScriptDebugClient, IUnknown)
{
STDMETHOD(NotifyDebugEvent)(_In_ ScriptDebugEventInformation *pEventInfo, _In_ IDataModelScript *pScript, _In_opt_ IModelObject *pEventDataObject, _Inout_ ScriptExecutionKind *resumeEventKind) PURE;
}
每當發生任何中斷腳本偵錯工具的事件時,偵錯程式碼本身會透過 NotifyDebugEvent 方法呼叫 介面。 這個方法是同步方法。 除非介面從 事件傳回,否則腳本不會繼續執行。 腳本偵錯工具的定義是簡單的:絕對不需要處理任何巢狀事件。 偵錯事件是由稱為 ScriptDebugEventInformation 的變體記錄所定義。 事件資訊中的哪些欄位有效,主要是由 DebugEvent 成員定義。 它會定義 ScriptDebugEvent 列舉成員所描述的事件種類。
呼叫堆疊:IDataModelScriptDebugStack
當發生中斷至腳本偵錯工具的事件時,偵錯介面會想要擷取中斷位置的呼叫堆疊。 這是透過 GetStack 方法完成的。 這類堆疊會透過定義如下的 IDataModelScriptDebugStack 來表示。
請注意,整體堆疊可能會跨越多個腳本和/或多個腳本提供者。 從特定腳本偵錯介面上對 GetStack 方法的單一呼叫傳回的呼叫堆疊,應該只會傳回該腳本範圍內呼叫堆疊的區段。 如果相同提供者的兩個腳本互動,腳本偵錯引擎可能會擷取呼叫堆疊,因為跨越多個腳本內容。 GetStack 方法不應該傳回位於另一個腳本中的堆疊部分。 相反地,如果偵測到這種情況,腳本中的界限框架應該透過該堆疊框架上的 IsTransitionPoint 和 GetTransition 方法實作,將本身標示為轉換框架。 偵錯工具介面預期會從存在的多個堆疊區段將整體堆疊結合在一起。
若要以這種方式實作轉換,或偵錯介面可能會將區域變數、參數、中斷點和其他腳本特定建構的查詢導向至錯誤的腳本內容! 這會導致偵錯工具介面中的未定義行為。
DECLARE_INTERFACE_(IDataModelScriptDebugStack, IUnknown)
{
STDMETHOD_(ULONG64, GetFrameCount)() PURE;
STDMETHOD(GetStackFrame)(_In_ ULONG64 frameNumber, _COM_Outptr_ IDataModelScriptDebugStackFrame **stackFrame) PURE;
}
GetFrameCount 方法會傳回呼叫堆疊此區段中的堆疊框架數目。 如果提供者可以偵測不同腳本內容或不同提供者中的畫面格,它應該透過在此堆疊區段中的 IsTransitionPoint 和 GetTransition 方法實作來向呼叫端表示。
GetStackFrame 會從堆疊區段取得特定的堆疊框架。 呼叫堆疊具有以零起始的索引系統:發生中斷事件的目前堆疊框架是框架 0。 目前方法的呼叫端是框架 1 (,依此類推) 。
檢查中斷狀態:IDataModelScriptDebugStackFrame
當中斷腳本偵錯工具時,呼叫堆疊的特定框架可以透過 IDataModelScriptDebugStack 介面上的 GetStackFrame 方法呼叫來擷取,代表發生中斷的堆疊區段。 傳回以表示此框架的 IDataModelScriptDebugStackFrame 介面定義如下。
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;
}
GetName 方法會傳回顯示名稱 (例如:此框架的函式名稱) 。 這類名稱會顯示在偵錯工具介面中向使用者顯示的堆疊回溯內。
GetPosition 方法會傳回堆疊框架所代表之腳本內的位置。 只有在腳本位於包含此畫面的堆疊所代表的中斷內時,才能呼叫這個方法。 此框架內的線條和資料行位置一律會傳回。 如果偵錯工具能夠傳回腳本內「執行位置」的範圍,則可以在 positionSpanEnd 引數中傳回結束位置。 如果偵錯工具無法這樣做,如果要求) 應該設定為零,則範圍結尾中的行和資料行值 (。
IDataModelScriptDebugStack 介面代表呼叫堆疊的區段,該部分的呼叫堆疊包含在一個腳本的內容中。 如果偵錯工具能夠偵測從一個腳本轉換到另一個腳本 (或一個腳本提供者到另一個) ,它可以藉由實作 IsTransitionPoint 方法並視情況傳回 true 或 false 來指出這一點。 呼叫堆疊框架,該框架會輸入套用區段的腳本,應該視為轉換點。 所有其他畫面都不是。
如果指定的堆疊框架是由 IsTransition 方法決定的轉換點, (請參閱該處的轉換點定義) 的檔,GetTransition 方法會傳回轉換的相關資訊。 特別是,這個方法會傳回先前的腳本-- 對包含這個 IDataModelScriptDebugStackFrame 之堆疊區段所表示之腳本進行呼叫的腳本。
Evaluate 方法會在呼叫此方法的 IDataModelScriptDebugStackFrame 介面所代表的堆疊框架內容中,評估腳本提供者語言的運算式) (。 運算式評估的結果必須封送處理出腳本提供者作為 IModelObject。 在產生的 IModelObject 上,屬性和其他建構都必須能夠在偵錯工具處於中斷狀態時取得。
EnumerateLocals 方法會傳回 IDataModelScriptDebugVariableSetEnumerator 介面所代表的變數集 (,這些變數是呼叫此方法之 IDataModelScriptDebugStackFrame 介面所代表之堆疊框架內容中範圍的所有區域變數) 。
EnumerateArguments 方法會傳回由 IDataModelScriptDebugVariableSetEnumerator 介面所代表的變數集 (,) 呼叫此方法之堆疊框架中所呼叫之函式的所有函式引數。
查看變數:IDataModelScriptDebugVariableSetEnumerator
腳本中要偵錯的變數集 (特定範圍中的變數、函式區域變數、函式的引數等等...) 是由透過 IDataModelScriptDebugVariableSetEnumerator 介面定義的變數集來表示:
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;
}
Reset 方法會將列舉值的位置重設為建立之後立即的位置,也就是在集合的第一個元素之前。
GetNext 方法會將列舉值移至集合中的下一個變數,並傳回變數的名稱、值,以及與其相關聯的任何中繼資料。 如果列舉值已到達集合結尾,則會傳回錯誤E_BOUNDS。 從 GetNext 方法傳回E_BOUNDS標記之後,除非進行插播重設呼叫,否則它會在再次呼叫時繼續產生E_BOUNDS。
中斷點:IDataModelScriptDebugBreakpoint
腳本中斷點是透過指定腳本偵錯介面上的 SetBreakpoint 方法來設定。 這類中斷點會以唯一識別碼和 IDataModelScriptDebugBreakpoint 介面的實作來表示,其定義如下。
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;
}
GetId 方法會將腳本提供者的偵錯引擎指派的唯一識別碼傳回中斷點。 此識別碼在包含腳本的內容中必須是唯一的。 中斷點識別碼可能是唯一的提供者;不過,這並非必要。
IsEnabled 方法會傳回是否啟用中斷點。 停用的中斷點仍然存在,而且仍在腳本的中斷點清單中,只是暫時「關閉」。 所有中斷點都應該以啟用狀態建立。
Enable 方法會啟用中斷點。 如果中斷點已停用,在呼叫此方法之後「達到中斷點」會導致中斷偵錯工具。
Disable 方法會停用中斷點。 在此呼叫之後,呼叫這個方法之後的「點擊中斷點」將不會中斷偵錯工具。 中斷點仍存在時,會被視為「已關閉」。
Remove 方法會從其包含清單中移除中斷點。 這個方法傳回之後,中斷點不再以語意方式存在。 代表中斷點的 IDataModelScriptDebugBreakpoint 介面會在呼叫之後視為孤立。 除了釋放它以外,其他任何專案都無法 () 在此呼叫之後完成。
GetPosition 方法會傳回腳本中中斷點的位置。 腳本偵錯工具必須傳回中斷點所在原始程式碼內的行和資料行。 如果能夠這樣做,它也可以填入 positionSpanEnd 引數所定義的結束位置,以傳回中斷點所代表的來源範圍。 如果偵錯工具無法產生這個範圍,而且呼叫端要求它,則範圍結束位置的 Line 和 Column 欄位應該填入為零,表示無法提供值。
中斷點列舉:IDataModelScriptDebugBreakpointEnumerator
如果腳本提供者支援偵錯,它也必須追蹤每個和每個腳本相關聯的所有中斷點,而且能夠列舉這些中斷點至偵錯介面。 中斷點的列舉值是透過指定腳本之偵錯介面上的 EnumerateBreakpoints 方法取得,並定義如下。
DECLARE_INTERFACE_(IDataModelScriptDebugBreakpointEnumerator, IUnknown)
{
STDMETHOD(Reset)() PURE;
STDMETHOD(GetNext)(_COM_Outptr_ IDataModelScriptDebugBreakpoint **breakpoint) PURE;
}
Reset 方法會將列舉值的位置重設為在建立列舉值之後的位置,也就是在第一個列舉中斷點之前。
GetNext 方法會將列舉值向前移至下一個要列舉的中斷點,並傳回該中斷點的 IDataModelScriptDebugBreakpoint 介面。 如果列舉值已經到達列舉的結尾,它會傳回E_BOUNDS。 產生E_BOUNDS錯誤之後,除非已對 Reset 方法進行插播呼叫,否則 GetNext 方法的後續呼叫會繼續產生E_BOUNDS。
另請參閱
本主題是一系列的一部分,描述可從 C++ 存取的介面、如何使用它們來建置 C++ 型偵錯工具延伸模組,以及如何利用其他資料模型建構 (例如:JavaScript 或 NatVis) 從 C++ 資料模型延伸模組。