【问题标题】:Can't activate projected type defined in IDL无法激活 IDL 中定义的投影类型
【发布时间】:2018-11-26 03:24:44
【问题描述】:

我试图在 IDL 中定义一个 Windows 运行时类型,并使用它的投影类型。从默认生成的Blank App UWP 项目(称为“Blank App”)开始,我添加了“MyControl.idl”

namespace BlankApp
{
    [default_interface]
    runtimeclass MyControl : Windows.UI.Xaml.Controls.Control
    {
        MyControl();
    }
}

编译解决方案,然后将 MyControl.hMyControl.cppGenerated Files/sources 复制到项目根目录。 p>

我包含了投影类型的标题并将以下代码添加到App::OnLaunched

#include <winrt/BlankApp.h>

...

void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
    auto const myControl{ winrt::BlankApp::MyControl() };
    ...

这一切都编译和链接得很好。在运行时,它会抛出一个hresult_error(0x80040154:REGDB_E_CLASSNOTREG 类未注册)。

引发异常时的调用堆栈顶部如下所示:

BlankApp.exe!winrt::hresult_error::hresult_error(const HRESULT code=REGDB_E_CLASSNOTREG Class not registered, winrt::hresult_error::from_abi_t __formal={...}) Line 2977  C++ Symbols loaded.
BlankApp.exe!winrt::throw_hresult(const HRESULT result=REGDB_E_CLASSNOTREG Class not registered) Line 3211  C++ Symbols loaded.
BlankApp.exe!winrt::check_hresult(HRESULT result=REGDB_E_CLASSNOTREG Class not registered) Line 3261    C++ Symbols loaded.
BlankApp.exe!winrt::impl::get_activation_factory<winrt::BlankApp::MyControl,winrt::Windows::Foundation::IActivationFactory>() Line 7375 C++ Symbols loaded.
BlankApp.exe!winrt::impl::factory_cache_entry<winrt::BlankApp::MyControl,winrt::Windows::Foundation::IActivationFactory>::get() Line 7448   C++ Symbols loaded.
BlankApp.exe!winrt::get_activation_factory<winrt::BlankApp::MyControl,winrt::Windows::Foundation::IActivationFactory>() Line 7520   C++ Symbols loaded.
BlankApp.exe!winrt::BlankApp::MyControl::MyControl() Line 74    C++ Symbols loaded.
BlankApp.exe!winrt::BlankApp::implementation::App::OnLaunched(const winrt::Windows::ApplicationModel::Activation::LaunchActivatedEventArgs & e={...}) Line 50   C++ Symbols loaded.

module.g.cpp 被编译到应用程序中并包含以下代码:

HRESULT __stdcall WINRT_GetActivationFactory(HSTRING classId, void** factory)
{
    try
    {
        *factory = nullptr;
        wchar_t const* const name = WindowsGetStringRawBuffer(classId, nullptr);

        if (0 == wcscmp(name, L"BlankApp.MainPage"))
        {
            *factory = winrt::detach_abi(winrt::make<winrt::BlankApp::factory_implementation::MainPage>());
            return S_OK;
        }

        if (0 == wcscmp(name, L"BlankApp.MyControl"))
        {
            *factory = winrt::detach_abi(winrt::make<winrt::BlankApp::factory_implementation::MyControl>());
            return S_OK;
        }

#ifdef _WRL_MODULE_H_
        return ::Microsoft::WRL::Module<::Microsoft::WRL::InProc>::GetModule().GetActivationFactory(classId, reinterpret_cast<::IActivationFactory**>(factory));
#else
        return winrt::hresult_class_not_available().to_abi();
#endif
    }
    catch (...)
    {
        return winrt::to_hresult();
    }
}

很明显,我的类型没有注册以供 Windows 运行时查找,尽管一切似乎都在它需要的位置。我缺少一些注册步骤吗?或者,这甚至由 UWP 应用程序支持,而不是 Windows 运行时组件?

【问题讨论】:

    标签: uwp windows-runtime c++-winrt


    【解决方案1】:

    您可能需要将该类添加到 appx 清单中。

    Extensions element documentation 中有一个示例。需要添加以下Extension 元素:

    <Extensions>
      <Extension Category="windows.activatableClass.inProcessServer">
        <InProcessServer>
          <Path>BlankApp.exe</Path>
          <ActivatableClass ActivatableClassId="BlankApp.MyControl" ThreadingModel="both" />
        </InProcessServer>
      </Extension>
    </Extensions>
    

    要允许 Windows 运行时检索激活工厂,还需要从可执行文件中导出 DllGetActivationFactory 符号。这可以通过将以下 .def 文件添加到项目中来完成:

    EXPORTS
    DllCanUnloadNow = WINRT_CanUnloadNow                    PRIVATE
    DllGetActivationFactory = WINRT_GetActivationFactory    PRIVATE
    

    【讨论】:

    • &lt;InProcessServer&gt; 添加&lt;Extension&gt; 元素(指定可执行文件的路径以及类型名称/线程模型)将错误更改为0x800401F9 (CO_E_ERRORINDLL)。据推测,WINRT_GetActivationFactory 符号需要导出(就像它在 Windows 运行时组件中一样)。但是,强制导出不会改变结果。尝试激活类型失败,错误代码为 0x800401F9。
    • 我的错,我正在导出装饰符号。使用 .def 文件导出DllGetActivationFactory(和DllCanUnloadNow)似乎已经解决了这个问题。我不确定这是否安全,或者是否有其他方法可以获得所需的功能。
    • def 文件是映射这些导出的支持方式。如果您从市场 (marketplace.visualstudio.com/…) 安装 VSIX 并创建“新 Windows 运行时组件 (C++ /WinRT)”项目,您将看到作为模板的一部分为您创建的 def 文件。
    • 我知道,使用 .def 文件是从可执行映像导出符号的受支持方式。我担心的是,从应用程序(相对于组件)导出这些符号是否安全。为一个类型声明一个可扩展点是不正确的,这是应用程序实现的内部。我也不知道,组件有什么特别之处,因此它们在系统查找类型工厂时受到尊重,没有 .appxmanifest。
    • 似乎不再需要手动导出Dll* 符号(不再需要了?)。这些导出由生成的文件App.xaml.g.hpp 通过#pragma 指令提供。我不知道这是由于更新了 VSIX 工具链,还是我的项目中的某些更改导致了 .hpp 文件被拉入。
    猜你喜欢
    • 2017-03-18
    • 1970-01-01
    • 2010-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-27
    • 1970-01-01
    相关资源
    最近更新 更多