Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu konu başlığında SDK uygulama ikili arabirimi (ABI) ile C++/WinRT nesneleri arasında dönüştürme adımları gösterilmektedir. Bu teknikleri kullanarak Windows Çalışma Zamanı ile programlamanın bu iki yolunu kullanan kodlar arasında birlikte çalışabilir veya kodunuzu ABI'den C++/WinRT'ye aşamalı olarak taşırken bunları kullanabilirsiniz.
Genel olarak C++/WinRT, platform üst bilgi dosyalarını eklemenize gerek kalmaması için ABI türlerini geçersiz* olarak kullanıma sunar.
Note
Kod örneklerinde, doğası gereği güvenli olmayan tür dönüştürmelerini açıkça belirtmek amacıyla static_cast yerine reinterpret_cast kullanırız.
ABI Windows Çalışma Zamanı nedir ve ABI türleri nelerdir?
Windows Çalışma Zamanı sınıfı (çalışma zamanı sınıfı) gerçekten soyutlamadır. Bu soyutlama, çeşitli programlama dillerinin bir nesneyle etkileşim kurmasına izin veren bir ikili arabirimi (Uygulama İkili Arabirimi veya ABI) tanımlar. Programlama dilinden bağımsız olarak, bir Windows Çalışma Zamanı nesnesiyle istemci kodu etkileşimi en düşük düzeyde gerçekleşir ve istemci dili yapıları nesnenin ABI'sine çağrılara çevrilir.
"%WindowsSdkDir%Include\10.0.17134.0\winrt" klasöründeki (gerekirse SDK sürüm numarasını ayarlayın) Windows SDK üst bilgileri, Windows Çalışma Zamanı ABI üst bilgi dosyalarıdır. MIDL derleyicisi tarafından üretildiler. Bu üst bilgilerden birini ekleme örneği aşağıda verilmiştir.
#include <windows.foundation.h>
Burada, söz konusu SDK üst bilgisinde bulabileceğiniz ABI türlerinden birinin basitleştirilmiş bir örneği verilmiştir. ABI ad alanına dikkat edin; Windows::Foundation ve diğer tüm Windows ad alanları, ABI ad alanı içindeki SDK üst bilgileri tarafından bildirilir.
namespace ABI::Windows::Foundation
{
IUriRuntimeClass : public IInspectable
{
public:
/* [propget] */ virtual HRESULT STDMETHODCALLTYPE get_AbsoluteUri(/* [retval, out] */__RPC__deref_out_opt HSTRING * value) = 0;
...
}
}
IUriRuntimeClass bir COM arabirimidir. Ama bundan da öte—temeli IInspectable olduğundan—IUriRuntimeClass bir Windows Çalışma Zamanı arabirimidir. Özel durumların oluşturulması yerine HRESULT dönüş türüne dikkat edin.
HSTRING tutamacı gibi öğelerin kullanımı da buna dahildir (işiniz bittiğinde bu tutamacı yeniden nullptr olarak ayarlamak iyi bir uygulamadır). Bu, Windows Çalışma Zamanı’ın uygulama ikili düzeyinde; diğer bir deyişle, COM programlama düzeyinde nasıl göründüğü hakkında fikir verir.
Windows Çalışma Zamanı Bileşen Nesne Modeli (COM) API'lerini temel alır. Windows Çalışma Zamanı bu şekilde erişebilir veya dil projeksiyonları aracılığıyla erişebilirsiniz. Projeksiyon, COM ayrıntılarını gizler ve belirli bir dil için daha doğal bir programlama deneyimi sağlar.
Örneğin, "%WindowsSdkDir%Include\10.0.17134.0\cppwinrt\winrt" klasörüne bakarsanız (gerekirse, durumunuzun SDK sürüm numarasını yeniden ayarlayın), C++/WinRT dil projeksiyon üst bilgilerini bulursunuz. Her Windows ad alanı için bir üst bilgi vardır; tıpkı her Windows ad alanı için bir ABI üst bilgisi bulunması gibi. C++/WinRT üst bilgilerinden birini ekleme örneği aşağıda verilmiştir.
#include <winrt/Windows.Foundation.h>
Ve o üst bilgi dosyasından, işte burada (basitleştirilmiş haliyle), az önce gördüğümüz ABI türünün C++/WinRT eşdeğeri yer alıyor.
namespace winrt::Windows::Foundation
{
struct Uri : IUriRuntimeClass, ...
{
winrt::hstring AbsoluteUri() const { ... }
...
};
}
Buradaki arabirim modern, standart C++. HRESULT'leri ortadan kaldırır (gerekirse C++/WinRT özel durumlar fırlatır). Ve erişim fonksiyonu, kapsamının sonunda temizlenen basit bir dize nesnesi döndürür.
Bu konu, Uygulama İkili Arabirimi (ABI) katmanında çalışan kodla birlikte çalışabilirlik sağlamak veya bu katmanda çalışan kodu taşımak istediğiniz durumlar içindir.
Koddaki ABI türlerine ve bu türlerden dönüştürme
Güvenlik ve kolaylık için, her iki yöndeki dönüştürmeler için winrt::com_ptr, com_ptr::as ve winrt::Windows::Foundation::IUnknown::as kullanabilirsiniz. Burada, ayrıca C++/WinRT projeksiyonu ile ABI arasında aksi takdirde ortaya çıkabilecek olası ad alanı çakışmalarını gidermek için farklı island’lar için ad alanı takma adlarını nasıl kullanabileceğinizi gösteren bir kod örneği yer alıyor (Konsol Uygulaması proje şablonunu temel alır).
// pch.h
#pragma once
#include <windows.foundation.h>
#include <unknwn.h>
#include "winrt/Windows.Foundation.h"
// main.cpp
#include "pch.h"
namespace winrt
{
using namespace Windows::Foundation;
}
namespace abi
{
using namespace ABI::Windows::Foundation;
};
int main()
{
winrt::init_apartment();
winrt::Uri uri(L"http://aka.ms/cppwinrt");
// Convert to an ABI type.
winrt::com_ptr<abi::IStringable> ptr{ uri.as<abi::IStringable>() };
// Convert from an ABI type.
uri = ptr.as<winrt::Uri>();
winrt::IStringable uriAsIStringable{ ptr.as<winrt::IStringable>() };
}
as işlevlerinin uygulamaları QueryInterface'i çağırır. Yalnızca AddRef'i çağıran alt düzey dönüştürmeler istiyorsanız winrt::copy_to_abi ve winrt::copy_from_abi yardımcı işlevlerini kullanabilirsiniz. Bu sonraki kod örneği, bu alt düzey dönüştürmeleri yukarıdaki kod örneğine ekler.
Önemli
ABI türleriyle birlikte çalışırken, kullanılan ABI türünün C++/WinRT nesnesinin varsayılan arabirimine karşılık olması kritik önem taşır. Aksi halde, ABI türü üzerindeki yöntem çağrıları gerçekte varsayılan arabirimde aynı vtable yuvasındaki yöntemleri çağırır; bu da son derece beklenmedik sonuçlara yol açar. Winrt::copy_to_abi tüm ABI türleri için void* kullandığından ve çağıranın türleri yanlış eşleştirmemeye dikkat ettiğini varsaydığından derleme zamanında buna karşı koruma sağlamadığını unutmayın. Bu, ABI türleri hiçbir zaman kullanılamayabileceği durumlarda ABI üst bilgilerine başvurmak için C++/WinRT üst bilgileri gerektirmekten kaçınmaktır.
int main()
{
// The code in main() already shown above remains here.
// Lower-level conversions that only call AddRef.
// Convert to an ABI type.
ptr = nullptr;
winrt::copy_to_abi(uriAsIStringable, *ptr.put_void());
// Convert from an ABI type.
uri = nullptr;
winrt::copy_from_abi(uriAsIStringable, ptr.get());
ptr = nullptr;
}
Aşağıda benzer şekilde düşük düzeyli dönüştürme teknikleri bulunur ancak bu kez ABI arabirim türlerine (Windows SDK üst bilgileri tarafından tanımlananlar) yönelik ham işaretçiler kullanılır.
// The code in main() already shown above remains here.
// Copy to an owning raw ABI pointer with copy_to_abi.
abi::IStringable* owning{ nullptr };
winrt::copy_to_abi(uriAsIStringable, *reinterpret_cast<void**>(&owning));
// Copy from a raw ABI pointer.
uri = nullptr;
winrt::copy_from_abi(uriAsIStringable, owning);
owning->Release();
Yalnızca adresleri kopyalayan en alt düzey dönüşümler için winrt::get_abi, winrt::detach_abi ve winrt::attach_abi yardımcı işlevlerini kullanabilirsiniz.
WINRT_ASSERT bir makro tanımıdır ve _ASSERTE genişletilir.
// The code in main() already shown above remains here.
// Lowest-level conversions that only copy addresses
// Convert to a non-owning ABI object with get_abi.
abi::IStringable* non_owning{ reinterpret_cast<abi::IStringable*>(winrt::get_abi(uriAsIStringable)) };
WINRT_ASSERT(non_owning);
// Avoid interlocks this way.
owning = reinterpret_cast<abi::IStringable*>(winrt::detach_abi(uriAsIStringable));
WINRT_ASSERT(!uriAsIStringable);
winrt::attach_abi(uriAsIStringable, owning);
WINRT_ASSERT(uriAsIStringable);
convert_from_abi işlevi
Bu yardımcı işlev ham ABI arabirim işaretçisini eşdeğer bir C++/WinRT nesnesine dönüştürür ve en az ek yüke sahiptir.
template <typename T>
T convert_from_abi(::IUnknown* from)
{
T to{ nullptr }; // `T` is a projected type.
winrt::check_hresult(from->QueryInterface(winrt::guid_of<T>(),
winrt::put_abi(to)));
return to;
}
İşlev, istenen C++/WinRT türünün varsayılan arabirimini sorgulamak için QueryInterface'i çağırır.
Gördüğümüz gibi, C++/WinRT nesnesinden eşdeğer ABI arabirim işaretçisine dönüştürmek için yardımcı işlev gerekli değildir. İstenen arabirimi sorgulamak için winrt::Windows::Foundation::IUnknown::as (veya try_as) üye işlevini kullanmanız yeterlidir. as ve try_as işlevleri, istenen ABI türünü saran bir winrt::com_ptr nesnesi döndürür.
convert_from_abi kullanan kod örneği
Bu yardımcı işlevi pratikte gösteren bir kod örneği aşağıda verilmiştir.
// pch.h
#pragma once
#include <windows.foundation.h>
#include <unknwn.h>
#include "winrt/Windows.Foundation.h"
// main.cpp
#include "pch.h"
#include <iostream>
using namespace winrt;
using namespace Windows::Foundation;
namespace winrt
{
using namespace Windows::Foundation;
}
namespace abi
{
using namespace ABI::Windows::Foundation;
};
namespace sample
{
template <typename T>
T convert_from_abi(::IUnknown* from)
{
T to{ nullptr }; // `T` is a projected type.
winrt::check_hresult(from->QueryInterface(winrt::guid_of<T>(),
winrt::put_abi(to)));
return to;
}
inline auto put_abi(winrt::hstring& object) noexcept
{
return reinterpret_cast<HSTRING*>(winrt::put_abi(object));
}
}
int main()
{
winrt::init_apartment();
winrt::Uri uri(L"http://aka.ms/cppwinrt");
std::wcout << "C++/WinRT: " << uri.Domain().c_str() << std::endl;
// Convert to an ABI type.
winrt::com_ptr<abi::IUriRuntimeClass> ptr = uri.as<abi::IUriRuntimeClass>();
winrt::hstring domain;
winrt::check_hresult(ptr->get_Domain(sample::put_abi(domain)));
std::wcout << "ABI: " << domain.c_str() << std::endl;
// Convert from an ABI type.
winrt::Uri uri_from_abi = sample::convert_from_abi<winrt::Uri>(ptr.get());
WINRT_ASSERT(uri.Domain() == uri_from_abi.Domain());
WINRT_ASSERT(uri == uri_from_abi);
}
ABI COM arabirim işaretçileriyle birlikte çalışma
Aşağıdaki yardımcı işlev şablonu, belirli bir türdeki ABI COM arabirim işaretçisinin eşdeğer C++/WinRT yansıtılan akıllı işaretçi türüne nasıl kopyalanmasını göstermektedir.
template<typename To, typename From>
To to_winrt(From* ptr)
{
To result{ nullptr };
winrt::check_hresult(ptr->QueryInterface(winrt::guid_of<To>(), winrt::put_abi(result)));
return result;
}
...
ID2D1Factory1* com_ptr{ ... };
auto cppwinrt_ptr {to_winrt<winrt::com_ptr<ID2D1Factory1>>(com_ptr)};
Bu bir sonraki yardımcı işlev şablonu buna eşdeğerdir; tek farkı, Windows Implementation Libraries (WIL) içindeki akıllı işaretçi türünden kopyalama yapmasıdır.
template<typename To, typename From, typename ErrorPolicy>
To to_winrt(wil::com_ptr_t<From, ErrorPolicy> const& ptr)
{
To result{ nullptr };
if constexpr (std::is_same_v<typename ErrorPolicy::result, void>)
{
ptr.query_to(winrt::guid_of<To>(), winrt::put_abi(result));
}
else
{
winrt::check_result(ptr.query_to(winrt::guid_of<To>(), winrt::put_abi(result)));
}
return result;
}
Ayrıca bkz . C++/WinRT ile COM bileşenlerini kullanma.
ABI COM arabirim işaretçileriyle güvenli olmayan birlikte çalışma
Aşağıdaki tabloda, belirli bir türdeki ABI COM arabirim işaretçisi ile eşdeğer C++/WinRT yansıtılan akıllı işaretçi türü arasındaki güvenli olmayan dönüştürmeler (diğer işlemlere ek olarak) gösterilir. Tablodaki kod için bu bildirimleri varsayın.
winrt::Sample s;
ISample* p;
void GetSample(_Out_ ISample** pp);
ISample'ınÖrnek için varsayılan arabirim olduğunu varsayalım.
Bu kodla derleme zamanında bunu onaylayabilirsiniz.
static_assert(std::is_same_v<winrt::default_interface<winrt::Sample>, winrt::ISample>);
| Operation | Nasıl yapılır | Notes |
|---|---|---|
| winrt::Sample'danISample* ayıklama | p = reinterpret_cast<ISample*>(get_abi(s)); |
s hâlâ nesnenin sahibidir. |
| Winrt::Sample'danISample* ayırma | p = reinterpret_cast<ISample*>(detach_abi(s)); |
artık nesnenin sahibi değil. |
| ISample* öğesini yeni winrt'e aktarma::Örnek | winrt::Sample s{ p, winrt::take_ownership_from_abi }; |
s nesnesinin sahipliğini alır. |
| ISample* değerini winrt::Sample olarak ayarlayın | *put_abi(s) = p; |
s nesnesinin sahipliğini alır. s'nin daha önce sahip olduğu tüm nesneler bellek sızıntısına neden olur (hata ayıklama modunda assert tetiklenir). |
| ISample* öğesini winrt::Sample içine alın | GetSample(reinterpret_cast<ISample**>(put_abi(s))); |
s nesnesinin sahipliğini alır. Daha önce sahip olduğu tüm nesneler sızdırılır (hata ayıklamada onaylanır). |
| winrt::Sample içinde ISample* değerini değiştirme | attach_abi(s, p); |
s nesnesinin sahipliğini alır. Daha önce s'ye ait olan nesne serbest bırakılır. |
| ISample* öğesini winrt::Sample konumuna kopyalama | copy_from_abi(s, p); |
s nesnesine yeni bir başvuru yapar. Daha önce s'ye ait olan nesne serbest bırakılır. |
| Winrt::Sample'ıISample'a kopyala* | copy_to_abi(s, reinterpret_cast<void*&>(p)); |
p nesnenin bir kopyasını alır. Daha önce p'ye ait olan tüm nesneler sızdırılır. |
ABI'nin GUID yapısıyla birlikte çalışma
GUID (/previous-versions/aa373931(v%3Dvs.80)) winrt::guid olarak yansıtılır. Uyguladığınız API'ler için GUID parametreleri için winrt::guid kullanmalısınız. Aksi takdirde, herhangi bir C++/WinRT üst bilgi dosyasını eklemeden önce unknwn.h dosyasını (<windows.h> ve diğer birçok üst bilgi dosyası tarafından örtük olarak dahil edilir) dahil ettiğiniz sürece, winrt::guid ile GUID arasında otomatik dönüşümler yapılır.
Eğer bunu yapmazsanız, o zaman aralarında zorlareinterpret_cast geçiş yapabilirsiniz. Aşağıdaki tablo için bu bildirimleri varsayın.
winrt::guid winrtguid;
GUID abiguid;
| Conversion |
#include <unknwn.h> ile |
#include <unknwn.h> olmadan |
|---|---|---|
| winrt::guid'denGUID'ye | abiguid = winrtguid; |
abiguid = reinterpret_cast<GUID&>(winrtguid); |
| GUID'denwinrt::guid'ye | winrtguid = abiguid; |
winrtguid = reinterpret_cast<winrt::guid&>(abiguid); |
Bunun gibi bir winrt::guid oluşturabilirsiniz.
winrt::guid myGuid{ 0xC380465D, 0x2271, 0x428C, { 0x9B, 0x83, 0xEC, 0xEA, 0x3B, 0x4A, 0x85, 0xC1} };
Bir dizeden winrt::guid oluşturma işlemini gösteren bir gist için bkz. make_guid.cpp.
ABI'nin HSTRING'i ile birlikte çalışma
Aşağıdaki tabloda winrt::hstring ve HSTRING ile diğer işlemler arasındaki dönüştürmeler gösterilir. Tablodaki kod için bu bildirimleri varsayın.
winrt::hstring s;
HSTRING h;
void GetString(_Out_ HSTRING* value);
| Operation | Nasıl yapılır | Notes |
|---|---|---|
| HSTRING'i hstring'denayıklama | h = reinterpret_cast<HSTRING>(get_abi(s)); |
s hâlâ dizeye sahip. |
| HSTRING'ihstring'den ayırma | h = reinterpret_cast<HSTRING>(detach_abi(s)); |
s artık dizenin sahibi değil. |
| HSTRING'ihstring olarak ayarlama | *put_abi(s) = h; |
s, dizenin sahipliğini devralır. Önceden s'ye ait olan tüm dizeler sızdırılır (debug modunda assert verir). |
| HSTRING'ihstring'e alma | GetString(reinterpret_cast<HSTRING*>(put_abi(s))); |
s dizenin sahipliğini devralır. Daha önce sahip olduğu tüm dizeler sızdırılır (hata ayıklamada onaylanır). |
| hstring içindeki HSTRING'i değiştirin | attach_abi(s, h); |
s dizenin sahipliğini devralır. Daha önce s'ye ait olan dize serbest bırakılır. |
| HSTRING'ihstring'e kopyalama | copy_from_abi(s, h); |
s dizenin özel bir kopyasını oluşturur. Daha önce s'nin sahip olduğu dize serbest bırakılır. |
| hstring'iHSTRING'e kopyalama | copy_to_abi(s, reinterpret_cast<void*&>(h)); |
h dizenin bir kopyasını alır. Daha önce h'ye ait olan tüm dizeler sızdırılır. |
Ayrıca, Windows Uygulama Kitaplıkları (WIL) dizesi yardımcıları temel dize işlemeleri gerçekleştirir. WIL dizesi yardımcılarını kullanmak için wil/resource.h< dosyasını ekleyin> ve aşağıdaki tabloya bakın. Tüm ayrıntılar için tablodaki bağlantıları izleyin.
| Operation | Daha fazla bilgi için WIL dize yardımcısı |
|---|---|
| Ham bir Unicode veya ANSI dize işaretçisi ve isteğe bağlı bir uzunluk sağlayın; uygun biçimde özelleştirilmiş bir unique_any sarmalayıcı edinin | wil::make_something_string |
| Ham, null ile sonlandırılmış bir Unicode dize işaretçisi bulunana kadar akıllı nesneyi sarmalından çıkarın | wil::str_raw_ptr |
Akıllı işaretçi nesnesinin sardığı dizeyi alın; ya da akıllı işaretçi boşsa boş dizeyi L"" |
wil::string_get_not_null |
| Herhangi bir sayıda dizeyi birleştirme | wil::str_concat |
| Printf stili biçim dizesinden ve karşılık gelen parametre listesinden bir dize alma | wil::str_printf |
Önemli API'ler
- AddRef işlevi
- QueryInterface işlevi
- winrt::attach_abi işlevi
- winrt::com_ptr yapı şablonu
- winrt::copy_from_abi işlevi
- winrt::copy_to_abi işlevi
- winrt::detach_abi işlevi
- winrt::get_abi işlevi
- winrt::Windows::Foundation::IUnknown::as member işlevi
- winrt::Windows::Foundation::IUnknown::try_as üye işlevi
Windows developer