在 UWP 和 win32 应用之间共享 DirectX texture2D

Shared DirectX texture2D between UWP and win32 app

提问人:UnclePooh 提问时间:8/22/2023 最后编辑:UnclePooh 更新时间:8/29/2023 访问量:141

问:

我正在尝试在 uwp 应用程序和 win32 应用程序之间设置共享的 2D 纹理。最小可重现示例使用 CoreApp 项目模板 (C++/WinRT),其中 App 类中的所有函数(Run 方法除外)均为空(Run 方法保持不变)。在 wWinMain 中,创建共享纹理并启动应用。

int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
// Create D3D11 Device and Context
ID3D11Device1* d3d11Device;
ID3D11DeviceContext1* d3d11DeviceContext;
{
    ID3D11Device* baseDevice;
    ID3D11DeviceContext* baseDeviceContext;
    D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_1 };
    UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;

    D3D11CreateDevice(
        0,
        D3D_DRIVER_TYPE_HARDWARE,
        0,
        creationFlags,
        featureLevels,
        ARRAYSIZE(featureLevels),
        D3D11_SDK_VERSION,
        &baseDevice,
        0,
        &baseDeviceContext);

    baseDevice->QueryInterface(__uuidof(ID3D11Device1), (void**)&d3d11Device);
    baseDevice->Release();

    baseDeviceContext->QueryInterface(__uuidof(ID3D11DeviceContext1), (void**)&d3d11DeviceContext);
    baseDeviceContext->Release();
}

HRESULT result;
D3D11_TEXTURE2D_DESC texDesc;
texDesc.Width = 360;
texDesc.Height = 360;
texDesc.MipLevels = 1;
texDesc.ArraySize = 1;
texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
texDesc.SampleDesc.Count = 1;
texDesc.SampleDesc.Quality = 0;
texDesc.Usage = D3D11_USAGE_DEFAULT;
texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_RENDER_TARGET;
texDesc.CPUAccessFlags = 0;
texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;

result = d3d11Device->CreateTexture2D(&texDesc, nullptr, &texture2D);

IDXGIResource1* pResource;
texture2D->QueryInterface(__uuidof(IDXGIResource1), (void**)&pResource);
result = pResource->CreateSharedHandle(
             nullptr,
             DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE,
             L"SharedTexture2D",
             &textureHandle);

CoreApplication::Run(make<App>());
}

Win32 应用基于添加了 main.cpp 文件的空项目。

#define WIN32_LEAN_AND_MEAN
#define NOMINMAX

#include <string>
#include <Userenv.h>
#include <windows.h>
#include <d3d11_1.h>
#include <windows.h>
#include <d3d11_1.h>
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "Userenv.lib")

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nShowCmd*/)
{
// Create D3D11 Device and Context as for uwp

// Try to open shared resource by name

// from Package.appmanifest of uwp project
constexpr auto packageFamilyName= L"b0660272-d6e8-493b-8da6-7e324d3652f3_6jxptbrcxhds4";

PSID psid{};
DeriveAppContainerSidFromAppContainerName(packageFamilyName, &psid);

auto path = std::wstring();
path.resize(256u);

ULONG returnedPathSize = 0u;

auto status = GetAppContainerNamedObjectPath(
    nullptr,
    psid,
    path.size(),
    (LPWSTR)(path.data()),
    &returnedPathSize);

path.insert(returnedPathSize - 1u, L"\\SharedTexture2D");

ID3D11Texture2D* texture;
auto result = d3d11Device->OpenSharedResourceByName(
    path.c_str(),
    DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE,
    __uuidof(ID3D11Texture2D),
    (void**)&texture);

return result;
}

UWP 创建共享句柄并返回S_OK。然后,我尝试从 win32 应用程序打开资源,并出现E_INVALIDARG一个或多个参数是无效的错误代码。

当我有两个 win32 应用程序时,上面的解决方案有效。问题是什么,我该如何处理?

我想它与UWP沙盒有关,也许需要设置一些安全属性或修改共享资源的名称,但我找不到任何信息。

提前致谢!

更新:

  1. 根据用户 Chuck Walbourn 的建议,我通过添加 DeriveAppContainerSidFromAppContainerName 修改了代码。

  2. 更精确的描述,以便更轻松地重现问题。

  3. 根据用户 @Simon Mourier 的建议 - 我已将包系列更改为包系列名称作为 DeriveAppContainerSidFromAppContainerName 的参数,它现在可以:)

winapi uwp directx direct3d11 dxgi

评论

0赞 Simon Mourier 8/22/2023
你有没有尝试过完全信任 stackoverflow.com/questions/42381582/......
0赞 UnclePooh 8/22/2023
是的,我试过了,但不幸的是,结果是一样的。
1赞 Simon Mourier 8/23/2023
您是否有可编译的可重复样品 stackoverflow.com/help/minimal-reproducible-example
0赞 UnclePooh 8/23/2023
@Simon Mourier,我修改了问题的描述,以便于重现问题。
2赞 Simon Mourier 8/25/2023
好的,你的问题是你的应用容器名称是错误的。不能使用“包名称”,而应使用“包系列名称”。双击 package.appxmanifest 的“打包”选项卡,它应该看起来像“bc5346ff-2b0e-4bc9-a456-5bdc380f6a35_ggxdvrfmnj0tt”(取决于你的密钥)。若要事先检查它是否良好,还可以使用进程黑客 2 工具并检查 UWP 进程 i.imgur.com/JvjF3ZD.png 的句柄(DeriveAppContainerSidFromAppContainerName 只是一个哈希函数,将任何内容作为输入)

答:

3赞 Chuck Walbourn 8/23/2023 #1

问题是 SharedTexture2D 不是完全限定的对象名称,因此当您从 Win32 应用程序使用它时,它不存在。

我相信您需要从 Win32 应用程序使用 GetAppContainerNamedObjectPath

有一些关于如何获取共享句柄以具有对特定 UWP SI 可见的正确权限的具体说明。请参阅 Microsoft Learn。您可以通过提供非 null 来使其工作,但这主要是 UWP 尝试打开由 Win32 应用创建的句柄的问题,这与你的方案相反。SECURITY_ATTRIBUTES

评论

0赞 UnclePooh 8/23/2023
我合并了 GetAppContainerNamedObjectPath 和 L“\\SharedTexture2D” 返回的应用程序容器名称,但最终结果是相同的 - 它不起作用。尽管如此,还是会发生E_INVALIDARG错误。
1赞 Chuck Walbourn 8/25/2023
我建议在 UWP 处于活动状态且对象存在时运行此 SysInternals 工具,以查看确切的命名约定。这并不是真正受支持的方案,因此几乎没有关于它的文档。
0赞 UnclePooh 8/25/2023
我以前不知道这个工具,但它似乎非常有用。谢谢!
1赞 YangXiaoPo-MSFT #2

正如@ChuckWalbourn和@SimonMourier所说,使用和确保是正确的。GetAppContainerNamedObjectPathDeriveAppContainerSidFromAppContainerNamepszAppContainerName

我们还可以从文档中学习 共享命名对象 @ChuckWalbourn 附加,

GetAppContainerNamedObjectPath将返回 基于其 SID 的打包应用程序。可以为 打包应用程序,方法是将其包系列名称传递给 。DeriveAppContainerSidFromAppContainerName

  • 注意
    在开发期间,可以通过 Visual Studio 中的包清单编辑器通过合作伙伴中心找到包系列名称 对于通过 Microsoft 商店发布的应用程序,或通过 Get-AppxPackage PowerShell 命令,用于已
    安装的应用程序。

打开由打包应用程序创建的命名对象时,请使用 格式<路径>\<名称>:

将 <PATH> 替换为创建应用程序的命名对象路径。
将 <NAME> 替换为对象名称。

  • 注意
    仅当打包的应用程序创建了对象时,才需要在对象名称前面加上前缀。命名对象创建者 Win32 应用程序不需要经过限定,但访问必须 在创建对象时仍被授予。