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.
C++/WinRT, Windows Çalışma Zamanı sınıflarını yazmanıza yardımcı olduğu gibi klasik Bileşen Nesne Modeli (COM) bileşenlerini (veya ortak sınıflarını) yazmanıza yardımcı olabilir. Bu konu size nasıl yapılacağını gösterir.
C++/WinRT'nin COM arabirimlerine göre varsayılan olarak nasıl davrandığı
C++/WinRT'nin winrt::implements şablonu, çalışma zamanı sınıflarınızın ve etkinleştirme fabrikalarınızın doğrudan veya dolaylı olarak türetildiği temel şablondur.
Varsayılan olarak winrt::implements klasik COM arabirimlerini sessizce yoksayar. Klasik COM arabirimleri için QueryInterface (QI) çağrıları E_NOINTERFACEile başarısız olur. Varsayılan olarak, winrt::implements yalnızca C++/WinRT arabirimlerini destekler.
- winrt::IUnknown bir C++/WinRT arabirimi olduğundan winrt::implementswinrt::IUnknowntabanlı arabirimleri destekler.
- Varsayılan olarak, winrt::implements, kendisini desteklemez.
Bir dakika içinde, varsayılan olarak desteklenmeyen örneklerin üstesinden nasıl geleceğinizi göreceksiniz. Ancak ilk olarak, varsayılan olarak ne olduğunu gösteren bir kod örneği verilmiştir.
// Sample.idl
namespace MyProject
{
runtimeclass Sample
{
Sample();
void DoWork();
}
}
// Sample.h
#include "pch.h"
#include <shobjidl.h> // Needed only for this file.
namespace winrt::MyProject::implementation
{
struct Sample : implements<Sample, IInitializeWithWindow>
{
IFACEMETHOD(Initialize)(HWND hwnd);
void DoWork();
}
}
Sample sınıfını kullanmak için istemci kodu aşağıda verilmiştır.
// Client.cpp
Sample sample; // Construct a Sample object via its projection.
// This next line doesn't compile yet.
sample.as<IInitializeWithWindow>()->Initialize(hwnd);
Klasik COM desteğini etkinleştirme
Kısaca, winrt::implements’in klasik COM arabirimlerini desteklemesi için yapılması gereken tek şey, C++/WinRT üst bilgilerini dahil etmeden önce unknwn.h üst bilgi dosyasını eklemektir.
Bunu açıkça veya ole2.hgibi başka bir üst bilgi dosyası ekleyerek dolaylı olarak yapabilirsiniz. Önerilen yöntemlerden biri, wil\cppwinrt.hparçası olan üst bilgi dosyasını eklemektir.
wil\cppwinrt.h üst bilgi dosyası, unknwn.h'in winrt/base.h'den önce eklenmesini sağlamakla kalmaz, ayrıca C++/WinRT ve WIL'ın birbirlerinin özel durumlarını ve hata kodlarını anlamasını da hazırlar.
Daha sonra, klasik COM arabirimleri için 'ı<> olarak kullanabilirsiniz ve yukarıdaki örnekteki kod derlenecektir.
Uyarı
Yukarıdaki örnekte, istemcide (sınıfı kullanan kod) klasik COM desteğini etkinleştirdikten sonra bile, sunucuda (sınıfı uygulayan kod) klasik COM desteğini etkinleştirmediyseniz, istemcide
Yerel (yansıtılmayan) bir sınıf
Yerel sınıf, aynı derleme biriminde (uygulama veya diğer ikili) hem uygulanan hem de kullanılan sınıftır; Ve bu yüzden bunun bir projeksiyonu yoktur.
İşte, yalnızca klasik COM arabirimlerini uygulayan bir yerel sınıf örneği.
struct LocalObject :
winrt::implements<LocalObject, IInitializeWithWindow>
{
...
};
Bu örneği uygularsanız ancak klasik COM desteğini etkinleştirmezseniz aşağıdaki kod başarısız olur.
winrt::make<LocalObject>(); // error: ‘first_interface’: is not a member of ‘winrt::impl::interface_list<>’
Yine, IInitializeWithWindow COM arabirimi olarak tanınmadığından C++/WinRT bunu yoksayar. LocalObject örneği söz konusu olduğunda, COM arabirimlerini yoksaymanın sonucu, LocalObject hiç arabirimi olmadığı anlamına gelir. Ancak her COM sınıfı en az bir arabirim uygulamalıdır.
COM bileşeninin basit bir örneği
C++/WinRT kullanılarak yazılmış basit bir COM bileşeni örneği aşağıda verilmiştır. Bu, bir mini uygulamanın tam listesidir, bu nedenle kodu yeni bir pch.h projesinin main.cpp ve yapıştırırsanız deneyebilirsiniz.
// pch.h
#pragma once
#include <unknwn.h>
#include <winrt/Windows.Foundation.h>
// main.cpp : Defines the entry point for the console application.
#include "pch.h"
struct __declspec(uuid("ddc36e02-18ac-47c4-ae17-d420eece2281")) IMyComInterface : ::IUnknown
{
virtual HRESULT __stdcall Call() = 0;
};
using namespace winrt;
using namespace Windows::Foundation;
int main()
{
winrt::init_apartment();
struct MyCoclass : winrt::implements<MyCoclass, IPersist, IStringable, IMyComInterface>
{
HRESULT __stdcall Call() noexcept override
{
return S_OK;
}
HRESULT __stdcall GetClassID(CLSID* id) noexcept override
{
*id = IID_IPersist; // Doesn't matter what we return, for this example.
return S_OK;
}
winrt::hstring ToString()
{
return L"MyCoclass as a string";
}
};
auto mycoclass_instance{ winrt::make<MyCoclass>() };
CLSID id{};
winrt::check_hresult(mycoclass_instance->GetClassID(&id));
winrt::check_hresult(mycoclass_instance.as<IMyComInterface>()->Call());
}
Ayrıca bkz. C++/WinRT ile COM bileşenlerini kullanma.
Daha gerçekçi ve ilginç bir örnek
Bu konunun geri kalanında, temel bir ortak sınıf (COM bileşeni veya COM sınıfı) ve sınıf fabrikası uygulamak için C++/WinRT kullanan en düşük konsol uygulaması projesi oluşturma adımları açıklanmaktadır. Örnek uygulama, üzerinde bir geri çağırma düğmesi bulunan bir bildirim bildiriminin nasıl teslim edileceğini gösterir ve coclass (INotificationActivationCallback COM arabirimini
Bildirim bildirimi özellik alanı hakkında daha fazla bilgi için bkz. Yerel bildirim bildirimi gönderme
Windows Konsol Uygulaması projesi oluşturma (ToastAndCallback)
Microsoft Visual Studio'da yeni bir proje oluşturarak başlayın. bir
pch.haçın ve C++/WinRT üst bilgilerinin eklenmesinden önce #include <unknwn.h> ekleyin. Sonuç şu şekildedir; pch.h içeriğini bu listeyle değiştirebilirsiniz.
// pch.h
#pragma once
#include <unknwn.h>
#include <winrt/Windows.Foundation.h>
main.cppaçın ve proje şablonunun oluşturduğu using-yönergelerini kaldırın. Onların yerine aşağıdaki kodu ekleyin (bize ihtiyacımız olan kitaplıkları, üst bilgileri ve tür adlarını verir). Sonuç şu şekildedir; main.cpp içeriğinizi bu listeyle değiştirebilirsiniz (aşağıdaki listede, daha sonra değiştireceğimiz işlev nedeniyle, main'deki kodu kaldırdık).
// main.cpp : Defines the entry point for the console application.
#include "pch.h"
#pragma comment(lib, "advapi32")
#pragma comment(lib, "ole32")
#pragma comment(lib, "shell32")
#include <iomanip>
#include <iostream>
#include <notificationactivationcallback.h>
#include <propkey.h>
#include <propvarutil.h>
#include <shlobj.h>
#include <winrt/Windows.UI.Notifications.h>
#include <winrt/Windows.Data.Xml.Dom.h>
using namespace winrt;
using namespace Windows::Data::Xml::Dom;
using namespace Windows::UI::Notifications;
int main() { }
Proje henüz derlenmez; Kod eklemeyi tamamladıktan sonra derlemeniz ve çalıştırmanız istenir.
Coclass'ı ve sınıf fabrikasını uygula
C++/WinRT'de, winrt::implements temel yapısından türeterek ortak sınıfları ve sınıf fabrikalarını uygularsınız. Yukarıda gösterilen üç using-yönergesinin hemen ardından (ve main'dan önce), toast bildirimi COM etkinleştirici bileşeninizi uygulamak için bu kodu yapıştırın.
static constexpr GUID callback_guid // BAF2FA85-E121-4CC9-A942-CE335B6F917F
{
0xBAF2FA85, 0xE121, 0x4CC9, {0xA9, 0x42, 0xCE, 0x33, 0x5B, 0x6F, 0x91, 0x7F}
};
std::wstring const this_app_name{ L"ToastAndCallback" };
struct callback : winrt::implements<callback, INotificationActivationCallback>
{
HRESULT __stdcall Activate(
LPCWSTR app,
LPCWSTR args,
[[maybe_unused]] NOTIFICATION_USER_INPUT_DATA const* data,
[[maybe_unused]] ULONG count) noexcept final
{
try
{
std::wcout << this_app_name << L" has been called back from a notification." << std::endl;
std::wcout << L"Value of the 'app' parameter is '" << app << L"'." << std::endl;
std::wcout << L"Value of the 'args' parameter is '" << args << L"'." << std::endl;
return S_OK;
}
catch (...)
{
return winrt::to_hresult();
}
}
};
struct callback_factory : implements<callback_factory, IClassFactory>
{
HRESULT __stdcall CreateInstance(
IUnknown* outer,
GUID const& iid,
void** result) noexcept final
{
*result = nullptr;
if (outer)
{
return CLASS_E_NOAGGREGATION;
}
return make<callback>()->QueryInterface(iid, result);
}
HRESULT __stdcall LockServer(BOOL) noexcept final
{
return S_OK;
}
};
Yukarıda belirtilen ortak sınıfın uygulanması, C++/WinRTile belirtilen
Yukarıdaki koddaki ortak sınıfta, kullanıcı bir toast bildirim ileti üzerindeki geri çağırma düğmesine tıkladığında çağrılan işlev olan INotificationActivationCallback::Activate yöntemini uygularız. Ancak bu işlevin çağrılabilmesi için önce ortak sınıfın bir örneğinin oluşturulması gerekir ve bu, IClassFactory::CreateInstance işlevinin işidir.
Az önce uyguladığımız ortak sınıf, bildirimler için COM etkinleştiricisi olarak bilinir ve yukarıda gördüğünüz callback_guid tanımlayıcısı (GUIDtürü) biçiminde sınıf kimliğine (CLSID) sahiptir. Bu tanımlayıcıyı daha sonra Başlat menüsü kısayolu ve Windows Kayıt Defteri girdisi biçiminde kullanacağız. COM etkinleştirici CLSID ve ilişkili COM sunucusunun yolu (burada oluşturduğumuz yürütülebilir dosyanın yoludur), bir bildirim geri bildirim düğmesine tıklandığında hangi sınıfın örneğini oluşturacağını belirleyen mekanizmadır (bildirim Bildirim Merkezi'nde tıklanmış olsa da olmasa da).
COM yöntemlerini uygulamak için en iyi yöntemler
Hata işleme ve kaynak yönetimi teknikleri el ele gidebilir. Özel durumları kullanmak hata kodlarından daha kullanışlı ve pratiktir. Resource-acquisition-is-initialization (RAII) deyimini kullanırsanız, hata kodlarını açıkça denetlemekten ve sonra kaynakları açıkça serbest bırakmaktan kaçınabilirsiniz. Bu tür açık denetimler kodunuzu gerekenden daha karmaşık hale getirir ve hatalara gizlenecek birçok yer sağlar. Bunun yerine RAII ve throw/catch özel durumları kullanın. Bu şekilde, kaynak ayırmalarınız özel durum açısından güvenlidir ve kodunuz basittir.
Ancak, COM yöntemi uygulamalarınızda istisnaların dışarı çıkmasına izin vermemelisiniz. COM yöntemlerinizde noexcept tanımlayıcısını kullanarak bunu sağlayabilirsiniz. Yönteminiz çıkmadan önce bunları işlediğiniz sürece, özel durumların yönteminizin çağrı grafiğinde herhangi bir yere atılması sorun değildir.
noexceptkullanıyorsanız ancak yönteminizden kaçmak için bir özel duruma izin verirseniz uygulamanız sonlandırılır.
Yardımcı türleri ve işlevleri ekleme
Bu adımda, kodun geri kalanının kullandığı bazı yardımcı türleri ve işlevleri ekleyeceğiz. Şimdi, main'in hemen öncesine aşağıdakileri ekleyin.
struct prop_variant : PROPVARIANT
{
prop_variant() noexcept : PROPVARIANT{}
{
}
~prop_variant() noexcept
{
clear();
}
void clear() noexcept
{
WINRT_VERIFY_(S_OK, ::PropVariantClear(this));
}
};
struct registry_traits
{
using type = HKEY;
static void close(type value) noexcept
{
WINRT_VERIFY_(ERROR_SUCCESS, ::RegCloseKey(value));
}
static constexpr type invalid() noexcept
{
return nullptr;
}
};
using registry_key = winrt::handle_type<registry_traits>;
std::wstring get_module_path()
{
std::wstring path(100, L'?');
uint32_t path_size{};
DWORD actual_size{};
do
{
path_size = static_cast<uint32_t>(path.size());
actual_size = ::GetModuleFileName(nullptr, path.data(), path_size);
if (actual_size + 1 > path_size)
{
path.resize(path_size * 2, L'?');
}
} while (actual_size + 1 > path_size);
path.resize(actual_size);
return path;
}
std::wstring get_shortcut_path()
{
std::wstring format{ LR"(%ProgramData%\Microsoft\Windows\Start Menu\Programs\)" };
format += (this_app_name + L".lnk");
auto required{ ::ExpandEnvironmentStrings(format.c_str(), nullptr, 0) };
std::wstring path(required - 1, L'?');
::ExpandEnvironmentStrings(format.c_str(), path.data(), required);
return path;
}
Kalan işlevleri ve wmain giriş noktası işlevini uygulama
main işlevinizi silin ve yerine ortak sınıfınızı kaydetmeye yönelik kodu içeren bu kod listesini yapıştırın. Ardından, uygulamanızı geri çağırabilen bir 'toast' sağlayın.
void register_callback()
{
DWORD registration{};
winrt::check_hresult(::CoRegisterClassObject(
callback_guid,
make<callback_factory>().get(),
CLSCTX_LOCAL_SERVER,
REGCLS_SINGLEUSE,
®istration));
}
void create_shortcut()
{
auto link{ winrt::create_instance<IShellLink>(CLSID_ShellLink) };
std::wstring module_path{ get_module_path() };
winrt::check_hresult(link->SetPath(module_path.c_str()));
auto store = link.as<IPropertyStore>();
prop_variant value;
winrt::check_hresult(::InitPropVariantFromString(this_app_name.c_str(), &value));
winrt::check_hresult(store->SetValue(PKEY_AppUserModel_ID, value));
value.clear();
winrt::check_hresult(::InitPropVariantFromCLSID(callback_guid, &value));
winrt::check_hresult(store->SetValue(PKEY_AppUserModel_ToastActivatorCLSID, value));
auto file{ store.as<IPersistFile>() };
std::wstring shortcut_path{ get_shortcut_path() };
winrt::check_hresult(file->Save(shortcut_path.c_str(), TRUE));
std::wcout << L"In " << shortcut_path << L", created a shortcut to " << module_path << std::endl;
}
void update_registry()
{
std::wstring key_path{ LR"(SOFTWARE\Classes\CLSID\{????????-????-????-????-????????????})" };
::StringFromGUID2(callback_guid, key_path.data() + 23, 39);
key_path += LR"(\LocalServer32)";
registry_key key;
winrt::check_win32(::RegCreateKeyEx(
HKEY_CURRENT_USER,
key_path.c_str(),
0,
nullptr,
0,
KEY_WRITE,
nullptr,
key.put(),
nullptr));
::RegDeleteValue(key.get(), nullptr);
std::wstring path{ get_module_path() };
winrt::check_win32(::RegSetValueEx(
key.get(),
nullptr,
0,
REG_SZ,
reinterpret_cast<BYTE const*>(path.c_str()),
static_cast<uint32_t>((path.size() + 1) * sizeof(wchar_t))));
std::wcout << L"In " << key_path << L", registered local server at " << path << std::endl;
}
void create_toast()
{
XmlDocument xml;
std::wstring toastPayload
{
LR"(
<toast>
<visual>
<binding template='ToastGeneric'>
<text>)"
};
toastPayload += this_app_name;
toastPayload += LR"(
</text>
</binding>
</visual>
<actions>
<action content='Call back )";
toastPayload += this_app_name;
toastPayload += LR"(
' arguments='the_args' activationKind='Foreground' />
</actions>
</toast>)";
xml.LoadXml(toastPayload);
ToastNotification toast{ xml };
ToastNotifier notifier{ ToastNotificationManager::CreateToastNotifier(this_app_name) };
notifier.Show(toast);
::Sleep(50); // Give the callback chance to display.
}
void LaunchedNormally(HANDLE, INPUT_RECORD &, DWORD &);
void LaunchedFromNotification(HANDLE, INPUT_RECORD &, DWORD &);
int wmain(int argc, wchar_t * argv[], wchar_t * /* envp */[])
{
winrt::init_apartment();
register_callback();
HANDLE consoleHandle{ ::GetStdHandle(STD_INPUT_HANDLE) };
INPUT_RECORD buffer{};
DWORD events{};
::FlushConsoleInputBuffer(consoleHandle);
if (argc == 1)
{
LaunchedNormally(consoleHandle, buffer, events);
}
else if (argc == 2 && wcscmp(argv[1], L"-Embedding") == 0)
{
LaunchedFromNotification(consoleHandle, buffer, events);
}
}
void LaunchedNormally(HANDLE consoleHandle, INPUT_RECORD & buffer, DWORD & events)
{
try
{
bool runningAsAdmin{ ::IsUserAnAdmin() == TRUE };
std::wcout << this_app_name << L" is running" << (runningAsAdmin ? L" (administrator)." : L" (NOT as administrator).") << std::endl;
if (runningAsAdmin)
{
create_shortcut();
update_registry();
}
std::wcout << std::endl << L"Press 'T' to display a toast notification (press any other key to exit)." << std::endl;
::ReadConsoleInput(consoleHandle, &buffer, 1, &events);
if (towupper(buffer.Event.KeyEvent.uChar.UnicodeChar) == L'T')
{
create_toast();
}
}
catch (winrt::hresult_error const& e)
{
std::wcout << L"Error: " << e.message().c_str() << L" (" << std::hex << std::showbase << std::setw(8) << static_cast<uint32_t>(e.code()) << L")" << std::endl;
}
}
void LaunchedFromNotification(HANDLE consoleHandle, INPUT_RECORD & buffer, DWORD & events)
{
::Sleep(50); // Give the callback chance to display its message.
std::wcout << std::endl << L"Press any key to exit." << std::endl;
::ReadConsoleInput(consoleHandle, &buffer, 1, &events);
}
Örnek uygulamayı test etme
Uygulamayı derleyin ve ardından, kaydın ve diğer kurulum kodunun çalışması için, en az bir kez yönetici olarak çalıştırın. Bunun bir yolu, Visual Studio'yu yönetici olarak çalıştırmak ve ardından uygulamayı Visual Studio'dan çalıştırmaktır. Görev çubuğunda Visual Studio'ya sağ tıklayarak atlama listesini görüntüleyin, atlama listesinde Visual Studio'ya sağ tıklayın ve ardından yönetici olarak çalıştırtıklayın. İstemi kabul edin ve projeyi açın. Uygulamayı çalıştırdığınızda, uygulamanın yönetici olarak çalışıp çalışmadığını belirten bir ileti görüntülenir. Değilse, kayıt ve diğer kurulum çalışmaz. Uygulamanın düzgün çalışması için bu kaydın ve diğer kurulumun en az bir kez çalışması gerekir.
Uygulamayı yönetici olarak çalıştırıp çalıştırmadığınıza bakılmaksızın, bir bildirim görüntülenmesine neden olmak için 'T' tuşuna basın. Ardından, açılan bildirimden veya İşlem Merkezi'nden doğrudan Geri Çağır ToastAndCallback düğmesine tıklayabilirsiniz ve bu işlem sonucunda uygulamanız başlatılır, coclass örneği oluşturulur ve INotificationActivationCallback::Activate yöntemi yürütülür.
İşlemdeki COM sunucusu
Yukarıdaki ToastAndCallback örnek uygulaması, yerel (veya işlem dışı) COM sunucusu olarak çalışır. Bu, ortak sınıfının CLSID'sini kaydetmek için kullandığınız LocalServer32 Windows Kayıt Defteri anahtarıyla gösterilir. Yerel COM sunucusu, ortak sınıflarını yürütülebilir bir ikili dosyada (.exe) barındırıyor.
Alternatif olarak (ve muhtemelen daha olası), ortak sınıflarınızı bir dinamik bağlantı kitaplığında (.dll) barındırmayı seçebilirsiniz. DLL biçimindeki bir COM sunucusu, işlem içi COM sunucusu olarak bilinir ve InprocServer32 Windows Kayıt Defteri anahtarı kullanılarak kaydedilen CLSID'ler tarafından belirtilir.
Dynamic-Link Kitaplığı (DLL) projesi oluşturma
Microsoft Visual Studio'da yeni bir proje oluşturarak işlem içi COM sunucusu oluşturma görevine başlayabilirsiniz. Visual C++>Windows Masaüstü>Dynamic-Link Kitaplığı (DLL) projesi oluşturun.
Yeni projeye C++/WinRT desteği eklemek için Windows Masaüstü uygulama projesini değiştirme bölümünde açıklanan adımları izleyerek C++/WinRT desteğiekleyin.
Coclass, sınıf fabrikası ve proc içi sunucu dışarı aktarmalarını uygulama
dllmain.cppaçın ve aşağıda gösterilen kod listesini ekleyin.
C++/WinRT Windows Çalışma Zamanı sınıflarını uygulayan bir DLL'niz zaten varsa, aşağıda gösterilen DllCanUnloadNow işlevine zaten sahip olursunuz. Bu DLL'ye ortak sınıflar eklemek istiyorsanız, DllGetClassObject işlevini ekleyebilirsiniz.
Uyumluluğunu korumak istediğiniz mevcut Windows Çalışma Zamanı C++ Şablon Kitaplığı (WRL) kodu yoksa, aşağıdaki koddan WRL bölümlerini kaldırabilirsiniz.
// dllmain.cpp
struct MyCoclass : winrt::implements<MyCoclass, IPersist>
{
HRESULT STDMETHODCALLTYPE GetClassID(CLSID* id) noexcept override
{
*id = IID_IPersist; // Doesn't matter what we return, for this example.
return S_OK;
}
};
struct __declspec(uuid("85d6672d-0606-4389-a50a-356ce7bded09"))
MyCoclassFactory : winrt::implements<MyCoclassFactory, IClassFactory>
{
HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject) noexcept override
{
try
{
return winrt::make<MyCoclass>()->QueryInterface(riid, ppvObject);
}
catch (...)
{
return winrt::to_hresult();
}
}
HRESULT STDMETHODCALLTYPE LockServer(BOOL fLock) noexcept override
{
// ...
return S_OK;
}
// ...
};
HRESULT __stdcall DllCanUnloadNow()
{
#ifdef _WRL_MODULE_H_
if (!::Microsoft::WRL::Module<::Microsoft::WRL::InProc>::GetModule().Terminate())
{
return S_FALSE;
}
#endif
if (winrt::get_module_lock())
{
return S_FALSE;
}
winrt::clear_factory_cache();
return S_OK;
}
HRESULT __stdcall DllGetClassObject(GUID const& clsid, GUID const& iid, void** result)
{
try
{
*result = nullptr;
if (clsid == __uuidof(MyCoclassFactory))
{
return winrt::make<MyCoclassFactory>()->QueryInterface(iid, result);
}
#ifdef _WRL_MODULE_H_
return ::Microsoft::WRL::Module<::Microsoft::WRL::InProc>::GetModule().GetClassObject(clsid, iid, result);
#else
return winrt::hresult_class_not_available().to_abi();
#endif
}
catch (...)
{
return winrt::to_hresult();
}
}
Zayıf referans desteği
Ayrıca bkz. C++/WinRT'de Zayıf başvurular.
C++/WinRT (özellikle, winrt::implements temel yapı şablonunu uygular), türünüz IInspectable (veya IInspectable'den türetilen herhangi bir arabirimi) uyguluyorsa, IWeakReferenceSource uygular.
Bunun nedeni IWeakReferenceSource ve IWeakReference Windows Çalışma Zamanı türleri için tasarlanmıştır. Bu nedenle, coclass için zayıf referans desteğini açmak amacıyla, uygulamanıza sadece winrt::Windows::Foundation::IInspectable (veya IInspectable'tan türeyen bir arabirim) ekleyebilirsiniz.
struct MyCoclass : winrt::implements<MyCoclass, IMyComInterface, winrt::Windows::Foundation::IInspectable>
{
// ...
};
Başka bir arabirimden türetilen bir COM arabirimi uygulama
Arabirim türetme, klasik COM'un bir özelliğidir (ve kasıtlı olarak Windows Çalışma Zamanı'nda bulunmaz). Aşağıda arabirim türetmesinin nasıl göründüğüne bir örnek verilmiştir.
IFileSystemBindData2 : public IFileSystemBindData { /* ... */ };
Örneğin, IFileSystemBindData
// pch.h
#pragma once
#include <Shobjidl.h>
...
// main.cpp
...
struct MyFileSystemBindData :
implements<MyFileSystemBindData,
IFileSystemBindData2>
{
// IFileSystemBindData
IFACEMETHOD(SetFindData)(const WIN32_FIND_DATAW* pfd) override { /* ... */ return S_OK; };
IFACEMETHOD(GetFindData)(WIN32_FIND_DATAW* pfd) override { /* ... */ return S_OK; };
// IFileSystemBindData2
IFACEMETHOD(SetFileID)(LARGE_INTEGER liFileID) override { /* ... */ return S_OK; };
IFACEMETHOD(GetFileID)(LARGE_INTEGER* pliFileID) override { /* ... */ return S_OK; };
IFACEMETHOD(SetJunctionCLSID)(REFCLSID clsid) override { /* ... */ return S_OK; };
IFACEMETHOD(GetJunctionCLSID)(CLSID* pclsid) override { /* ... */ return S_OK; };
};
...
int main()
...
Sonraki adım, QueryInterface'in doğrudan veya dolaylı olarak MyFileSystemBindDataörneği için IID_IFileSystemBindData (temel arabirim) çağrıldığında başarılı olduğundan emin olmaktır. Bunu yapmak için winrt::is_guid_of işlev şablonu için bir uzmanlık sağlamalısınız.
winrt::is_guid_of değişkendir ve bu nedenle arabirimlerin listesini sağlayabilirsiniz. IFileSystemBindData2
// pch.h
...
namespace winrt
{
template<>
inline bool is_guid_of<IFileSystemBindData2>(guid const& id) noexcept
{
return is_guid_of<IFileSystemBindData2, IFileSystemBindData>(id);
}
}
// main.cpp
...
int main()
{
...
auto mfsbd{ winrt::make<MyFileSystemBindData>() };
auto a{ mfsbd.as<IFileSystemBindData2>() }; // Would succeed even without the **is_guid_of** specialization.
auto b{ mfsbd.as<IFileSystemBindData>() }; // Needs the **is_guid_of** specialization in order to succeed.
}
winrt::is_guid_of uzmanlığı, projedeki tüm dosyalarda aynı olmalı ve arabirim, winrt::implements ya da winrt::delegate şablonu tarafından kullanılırken görünür olmalıdır. Genellikle bunu ortak bir üst bilgi dosyasına koyarsınız.
Önemli API'ler
İlgili konular
- C++/WinRT ile API'leri Oluşturma
- C++/WinRT ile COM bileşenlerini kullanma
- Yerel bir toast bildirimi gönder