Advanced 主題和速記
縮寫
如果您在未指定命名空間的情況下使用參數型別,則 MIDL 3.0 編譯器會在 Windows 中尋找它。基礎. 集合命名空間。 在實務上,這表示您可以使用下列速記。
簡短版本 | 完整版本 |
---|---|
IIterable<T> | Windows。Iiterable |
Iiterator |
Windows。Iiterator |
Inputiterator | Windows。Inputiterator |
IMap < K、V> | Windows。基礎. 集合. IMap < K,V> |
IMapChangedEventArgs < K> | Windows。IMapChangedEventArgs < K> |
IMapView<K, V> | Windows。IMapView < K,V> |
Iobservablemap 且 < K,V> | Windows。Iobservablemap 且 < K,V> |
IObservableVector < T> | Windows。IObservableVector < T> |
IVector<T> | Windows。IVector < T> |
IVectorView<T> | Windows。IVectorView < T> |
MapChangedEventHandler < K,V> | Windows。MapChangedEventHandler < K,V> |
VectorChangedEventHandler < T> | Windows。VectorChangedEventHandler < T> |
這種機制並不適用于Windows。基礎命名空間。 例如,您必須撰寫 Windows 的完整名稱。IAsyncAction。
多載
多載方法和函式的預設行為是在介面內的第二個和後續多載的 ABI 名稱後面附加數位尾碼。
[contract(Windows.Foundation.UniversalApiContract, 1)]
runtimeclass Sample
{
// ABI name is "DoSomething"
void DoSomething();
// ABI name is "DoSomething2"
void DoSomething(Int32 intensity);
[contract(Windows.Foundation.UniversalApiContract, 2)]
{
// ABI name is "DoSomething" (new interface)
void DoSomething(Int32 intensity, String label);
}
}
此預設命名不符合建議的 API 設計指導方針,因此請使用 [method_name] 屬性加以覆寫。
[contract(Windows.Foundation.UniversalApiContract, 1)]
runtimeclass Sample
{
void DoSomething();
[method_name("DoSomethingWithIntensity")]
void DoSomething(Int32 intensity);
[contract(Windows.Foundation.UniversalApiContract, 2)]
{
[method_name("DoSomethingWithIntensityAndLabel")]
void DoSomething(Int32 intensity, String label);
}
}
執行非 exclusiveto 介面
從介面衍生您的執行時間類別,會自動宣告該介面的成員。 請勿重新宣告它們。 如果您這樣做,MIDL 3.0 編譯器會假設您想要執行另一個方法 M () ,以隱藏介面中的方法。
interface I
{
void M();
}
runtimeclass C : I
{
// Don't redeclare M(). It's automatically inherited from interface I.
// void M();
}
指定預設介面
如果您未指定預設介面,MIDL 3.0 編譯器會選擇第一個實例介面。 若要覆寫此選項,請在您想要成為預設介面的介面之前插入屬性 [default]
。
// Declaring an external interface as the default
runtimeclass C : [default]I { ... }
// Declaring a specific exclusiveto interface as the default.
// This is very unusual.
runtimeclass C
{
...
[default][interface_name(...)]
{
...
}
}
回溯相容性屬性
如果您要將 MIDL 1.0 或 MIDL 2.0 轉換成 MIDL 3.0 (也請參閱 從傳統 midlrt.exe 根據) 轉換到 midl 3.0 ,您將需要自訂通常自動產生的專案,讓自動產生的值符合現有的值。
- 若要指定介面的名稱和 UUID,請使用
[interface_name("fully.qualified.name", UUID)]
屬性。 - 若要指定 factory 介面的名稱和 UUID,請使用
[constructor_name("fully.qualified.name", UUID)]
屬性。 - 若要指定靜態介面的名稱和 UUID,請使用
[static_name("fully.qualified.name", UUID)]
屬性。 - 若要指定輸出參數的名稱,請使用
[return_name("name")]
屬性。 - 若要指定方法的名稱,請使用
[method_name("name")]
屬性。
、 constructor_name
和 static_name
屬性的 "UUID" 部分 interface_name
是選擇性的。 如果省略,MIDL 會自動產生 IID。
[contract(Windows.Foundation.UniversalApiContract, 1)]
[interface_name("ISample", ceb27355-f772-407c-9540-6467a7199bc7)]
[constructor_name("ISampleFactory", 863B201F-BC7B-471E-A066-6425E8E639EC)]
[static_name("ISampleStatics", 07254c86-3b01-4e24-b52b-14e832c15483)]
runtimeclass Sample
{
[method_name("CreateWithIntensity")]
Sample(Int32 intensity);
static Boolean ShowConfigurationUI();
[return_name("count")]
Int32 GetCount();
[constructor_name("ISampleFactory2", FEA29CEC-7768-41DE-9A46-CAAAA4622588)]
[static_name("ISampleStatics2", 191235b5-a7b5-456f-86ea-abd1a735c6ab)]
[interface_name("ISample2", d870ed2e-915a-48a2-ad17-c05efa123db7)]
[contract(Windows.Foundation.UniversalApiContract, 2)]
{
[method_name("CreateWithIntensityAndLabel")]
Sample(Int32 intensity, String label);
static Boolean IsSupported();
[return_name("success")]
Boolean TrySomething();
}
}
如果您讓 xxx_name
批註混淆,MIDL 3.0 編譯器將不會警告您。 例如,下列範例會編譯而不會發生錯誤,即使沒有任何實例成員要放在介面中 interface_name
也一樣。 屬性存在 interface_name
時,會產生名為 ISampleFactory2 的空介面。
[contract(Windows.Foundation.UniversalApiContract, 1)]
[interface_name("ISample", ceb27355-f772-407c-9540-6467a7199bc7)]
runtimeclass Sample
{
[return_name("count")]
Int32 GetCount();
// !WRONG! Should be constructor_name.
[interface_name("ISampleFactory2", FEA29CEC-7768-41DE-9A46-CAAAA4622588)]
[contract(Windows.Foundation.UniversalApiContract, 2)]
{
// MIDL will autogenerate ISampleFactory since there is no [constructor_name]
Sample(Int32 intensity);
}
}
空白類別
雖然這種使用方式有點模糊,但有時候必須撰寫空白類別 (沒有成員) 的類別,或是空的 factory 類別。 這種情況的常見範例是使用 EventArgs 類別。 如果引入了事件,有時不需要事件的引數, (收到信號的事件不需要額外的內容) 。 我們的 API 設計指導方針強烈建議您提供 EventArgs 類別,讓類別能夠在未來加入新的事件引數。 不過,請考慮這個空的類別。
runtimeclass MyEventsEventArgs
{
}
該類別會產生此錯誤。
error MIDL5056 : [msg]a runtime class without a default attribute cannot be used as a parameter. Runtime classes must have methods or be flagged as marker classes if they are used as a parameter [context]: Windows.Widgets.MyEventsEventArgs [ RuntimeClass 'Windows.Widgets.MyEventsEventArgs' ( Parameter 'result' ) ]
有幾種方式可以修正此問題。 最簡單的方法是使用 [default_interface]
屬性來表示缺少的方法是刻意的,而不是撰寫錯誤。 方法如下所示。
// An empty runtime class needs a [default_interface] tag to indicate that the
// emptiness is intentional.
[default_interface]
runtimeclass MyEventsEventArgs
{
}
修正的 [interface_name]
另一種方法是使用屬性。 如果 MIDL 在沒有一般方法的類別上遇到 [interface_name]
, (或未) 一般方法的已建立版本的區塊,則會為該區塊產生空的介面。 同樣地,如果 [static_name]
或 [constructor_name]
屬性存在於類別或已建立版本的區塊中,而且沒有靜態 (或) 的函式,則會為該靜態介面或函式產生空白的介面。
請小心不要混淆空的類別與靜態類別。 您可以有空白類別的實例 (雖然它們不會) ,但您不能有靜態類別的實例。
空白介面
空的介面 (也稱為標記介面) 必須指定明確 [uuid(...)]
的介面。
// An empty interface must specify an explicit [uuid] to ensure uniqueness.
[uuid("94569FA9-D3BB-4D01-BF7C-B8E1D8F8B30C")]
[contract(Windows.Foundation.UniversalApiContract, 1)]
interface ISomethingMarker
{
}
如果您忘了,則會產生此錯誤。
error MIDL4010 : [msg]Cannot find the guid attribute of an interface or a delegate. [context]Windows.Widgets.ISomethingMarker
自動產生的 Uuid 是介面內容的雜湊,但如果是針對空的介面進行的,則所有標記介面最後都會有相同的 UUID。
範圍列舉
如果您將命令參數傳遞 /enum_class
給 MIDL 3.0 編譯器,則編譯器發出的列舉會宣告為範圍列舉, (列舉類別) 。 請勿針對公用類型使用範圍列舉。
撰寫和啟用
如需可 組合 類別的詳細資訊,請參閱 XAML 控制項; 系結至 c + +/WinRT 屬性。
您可以指定 unsealed runtimeclass
建立可組合的類別。 此外,您可以指定 unsealed runtimeclass unsealed
,指出類別是使用 COM 匯總,還是定期啟用。 這對具有公用函式的基類而言很重要。
解讀錯誤訊息
error MIDL2025: [msg]syntax error [context]: expecting > or, near ">>"
如果您撰寫 IAsyncOperation<IVectorView<Something>>
, >>
則會將轉譯為右移運算子。 若要解決這個問題,請在兩個大於正負號之間放置一個空格來提供 IAsyncOperation<IVectorView<Something> >
。
error MIDL2025: [msg]syntax error [context]: expecting . near ","
如果您指定了不存在的合約(可能是因為打字錯誤),就會發生此錯誤。
[contract(Windows.Foundation.UniversalApiContact, 5)]
^^^^^^^ typo
error MIDL5082: [msg]the version qualifying an enum's field cannot be less than the version of the enum itself
此錯誤訊息不僅會針對錯誤訊息中的原因產生,也會在您嘗試將列舉的欄位放入不同的合約時產生。 將列舉的欄位屬於相同合約的不同版本是合法的,但它們不能完全位於不同的合約中。
error MIDL5161: [msg]Invalid method parameter name [context]: Parameter 'result' (or 'operation' or 'value')
參數名稱 result
和 operation
會保留于方法中。 參數名稱 value
是在函式中保留。
error MIDL5023: [msg]the arguments to the parameterized interface are not valid
檢查您是否已正確拼寫介面名稱。
不要在單一介面內混用 MIDL 2.0 和 MIDL 3。0
每個介面和執行時間類別都必須是完全 MIDL 2.0 或完全 MIDL 3.0。 從 MIDL 2.0 執行時間類別參考 MIDL 3.0 介面 是 合法的。
如果您嘗試混合 MIDL 2.0 和 MIDL 3.0,則編譯器會將整個實體視為 MIDL 2.0,這會導致編譯器錯誤。 如果您在想要使用 MIDL 3.0 時不小心使用 MIDL 2.0 語法,您可能會遇到這個問題。
interface ICollapsible
{
void Collapse();
boolean IsCollapsed { get; } // WRONG!
// ^^^^^^^ Lowercase "boolean" is MIDL 2.0.
Boolean IsCollapsed { get; } // RIGHT!
// ^^^^^^^ Uppercase "Boolean" is MIDL 3.0.
};
傳回HRESULT的委派
傳回 HRESULT 的委派不明確。 這可以是傳統的 (前置 MIDL 3.0) 委派的宣告,名義上會傳回 void (其中 HRESULT 用來傳播例外狀況) ,或是名義上傳回 HRESULT之委派的新式 (MIDL 3.0) 宣告。
編譯器會藉由查看宣告的其他部分,來解析不明確的部分。 例如,如果使用傳統語法來宣告參數,則會假設宣告為傳統。 如果以新式語法宣告參數,則會假設宣告為新式。
delegate HRESULT AmbiguousDelegate(INT32 value, RuntimeClassName* r);
- 參數使用傳統語法,因此假設為傳統宣告。
- 最新的對等專案是
delegate void AmbiguousDelegate(Int32 value, RuntimeClassName r);
。
delegate HRESULT AmbiguousDelegate(Int32 value, RuntimeClassName r);
- 參數使用新式語法,因此假設為新式宣告。
- 傳統的對等專案是
delegate HRESULT AmbiguousDelegate(Int32 value, RuntimeClassName* r, [out, retval] HRESULT* result);
。
有時候,參數清單不足以解決不明確的問題。 例如,空的參數清單,或只包含列舉的參數清單,在傳統和新式語法中都是合法的。 在這種情況下,MIDL 3.0 編譯器會預設為傳統。
delegate HRESULT AmbiguousDelegate(MyEnum e);
- 解釋為傳統委派,其中委派名義上會傳回 void,而 HRESULT 則用於傳播例外狀況。
- 如果您真的想要傳回 HRESULT的委派,您需要使用傳統語法:
delegate HRESULT AmbiguousDelegate(MyEnum e, [out, retval] HRESULT* result);
。
幸運的是,名義上會傳回 HRESULT的委派很少見。
JavaScript 和 Visual Basic 中的輸出參數
如需輸出參數的背景資訊,請參閱 參數 。
JavaScript 會使用與 out
大部分語言不同的參數來投影方法。 如果方法的傳回型別為 void,而且它具有單一 out
參數, out
則方法會傳回參數。 否則,方法會傳回單一物件;該物件的每個 out
參數都有一個屬性,再加上另一個傳回值的屬性 (if not void) 。 在下列範例中,方法呼叫所傳回的 JavaScript 物件具有名為 result的屬性,以及另一個名為 餘數的屬性。
runtimeclass Test
{
static void Divide(Int32 x, Int32 y, out Int32 result, out Int32 remainder);
}
Visual Basic 不支援 out
唯一的參數。 具有 out
參數的方法會依 Visual Basic ByRef
處理。