For the past couple of days, I've been trying to learn WinRT, working with the manifests, loading the C++ or C# DLLs, etc. The next logical step for me was to try to build a plugin system that loads my WinRT DLLs that can be written in C++ or C# into my Win32 apps. This seems to be a bit more of a challenge because of unclear documentation. What makes this even more unclear to me is the underlying usage of COM and WRL which I don't have experience with. I've prepared a minimal viable example on GitHub for anyone that could help me figure this out.
A bit of elaboration on why C++/WinRT is only being used from step 6. I'm aiming at building a plugin system around dynamically/runtime loaded DLLs. I don't want to have any explicit references to DLLs or WinMD files in my projects. The goal is to basically have a Win32 application that has a statically linked abstraction project that contains the WinRT generated header files and a set of DLLs that also make use of the same abstraction project and are dynamically loaded during the runtime of the Win32 application. I've built these kind of systems before for C++ and C# but I feel lost with the WinRT layers and which methods to call when to utilize the WinRT factories correctly.
Everything seems to be working fine until step 6 when I'm not sure what would come next.
typedef HRESULT(WINAPI *dllAbstractionFactoryFp)(HSTRING activableClassId, IActivationFactory **factory);
...
// #### 0. Prep
HRESULT hRes;
// #### 1. Load DLL into memory
HMODULE hLibrary;
hLibrary = LoadLibrary(L"TicketMachine.dll");
//hLibrary = ::LoadLibraryEx(L"TicketMachine.dll", NULL, NULL);
if (!hLibrary) return EXIT_FAILURE;
// #### 2. Get the pointer to the DllGetActivationFactory of the loaded DLL
dllAbstractionFactoryFp abstractionFactoryFp;
abstractionFactoryFp = (dllAbstractionFactoryFp)GetProcAddress(hLibrary, "DllGetActivationFactory");
if (!abstractionFactoryFp) return EXIT_FAILURE;
// #### 3. Define the class name to activate
HSTRING activableClassName;
WindowsCreateString(L"TicketMachine.Ticket", 20, &activableClassName);
if (!activableClassName) return EXIT_FAILURE;
// #### 4. Set the activation factory
IActivationFactory* activationFactoryP;
hRes = (abstractionFactoryFp)(activableClassName, &activationFactoryP);
if (!activationFactoryP || hRes != S_OK) return EXIT_FAILURE;
// #### 5. Get the runtime class name to check if everything is going fine
HSTRING className;
activationFactoryP->GetRuntimeClassName(&className);
if (!className) return EXIT_FAILURE;
// #### 6. The identification GUID
IID iid = winrt::guid_of<winrt::TicketMachine::ITicketFactory>();
winrt::TicketMachine::ITicketFactory* iTicketFactory;
hRes = activationFactoryP->QueryInterface(iid, (void**) & iTicketFactory); // iTicketFactory stays uninitialized
if (!iTicketFactory || hRes != S_OK) return EXIT_FAILURE;
// ### ?. ...
;
// #### ?. Profit???
;
With an explicitly linked WinMD file I can just call the class constructor or even the ::impl::call_factory
method that will instantiatie the object for me. This of course won't work if the DLL is loaded dynamically on runtime.
winrt::TicketMachine::Ticket staTicket;
// or
winrt::Windows::Foundation::IInspectable baseInterface, innerInterface;
winrt::TicketMachine::Ticket ticket = winrt::impl::call_factory<winrt::TicketMachine::Ticket, winrt::TicketMachine::ITicketFactory>([&](winrt::TicketMachine::ITicketFactory const& f) { return f.CreateInstance(baseInterface, innerInterface); });
This is the GitHub repository where I've prepared this code and which should compile and run out of the box, https://github.com/zborowa/winrt-dynamic-dll-loading
FYI, I've already seen the following questions and also found the following resources:
- Loading WinRT component without referencing the DLL/assembly
- Consuming a DLL(Universal Apps) from a WinRT Component
- Creating WinRT component with static methods in C++ / WRL
- https://devblogs.microsoft.com/oldnewthing/20201118-00/?p=104459
- https://gist.github.com/clarkezone/43e984fb9bdcd2cfcd9a4f41c208a02f
- These Aren't the COM Objects You're Looking For
- And many more...