IPC: UWP C# pipe client fails on connect C++ server

后端 未结 2 872
一整个雨季
一整个雨季 2020-12-20 10:21

I am trying to use NamedPipe to communicate between app and service in Win10. APP is developed with C#(UWP),running foreground as Pipe Client. And service is C++ running b

相关标签:
2条回答
  • 2020-12-20 11:01

    when named pipe created from UWP process (appcontainer) name must have form

    "\\\\?\\pipe\\local\\SomeName"

    system convert this name to

    "\\\\?\\pipe\\Sessions\\<SessionId>\\AppContainerNamedObjects\\<AppContainerSid>\\SomeName"

    so desktop application must create pipe with such name format for UWP be able open it. but for this need know appcontainer-sid for uwp app and it session id. ok, appcontainer-sid is permanent for concrete UWP - never changed, but SessionId can be different (usually 1 but can be and another). also need set special security descriptor on pipe, which grant access for SDDL_EVERYONE + SDDL_ALL_APP_PACKAGES + SDDL_ML_LOW. for example

    "D:(A;;GA;;;WD)(A;;GA;;;AC)S:(ML;;;;;LW)"

    example of create such pipe in desktop

    inline ULONG BOOL_TO_ERROR(BOOL f)
    {
        return f ? NOERROR : GetLastError();
    }
    
    volatile UCHAR guz = 0;
    
    ULONG CreatePipeforUWP(OUT PHANDLE PipeHandle, PCWSTR PipeName, HANDLE hProcess)
    {
        SECURITY_ATTRIBUTES sa = { sizeof(sa), 0, FALSE };
    
        // SDDL_EVERYONE + SDDL_ALL_APP_PACKAGES + SDDL_ML_LOW
        if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(
            L"D:(A;;GA;;;WD)(A;;GA;;;AC)S:(ML;;;;;LW)", 
            SDDL_REVISION_1, &sa.lpSecurityDescriptor, 0))
        {
            return GetLastError();
        }
    
        HANDLE hToken;
    
        ULONG err = BOOL_TO_ERROR(OpenProcessToken(hProcess, TOKEN_QUERY, &hToken));
    
        if (err == NOERROR)
        {
            PVOID stack = alloca(guz);
    
            ULONG cb = 0, rcb = 128;
    
            union {
                PVOID buf;
                PTOKEN_APPCONTAINER_INFORMATION AppConainer;
                PWSTR sz;
            };
    
            do 
            {
                if (cb < rcb)
                {
                    cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
                }
    
                err = BOOL_TO_ERROR(GetTokenInformation(hToken, ::TokenAppContainerSid, buf, cb, &rcb));
    
                if (err == NOERROR)
                {
                    ULONG SessionId;
    
                    err = BOOL_TO_ERROR(GetTokenInformation(hToken, ::TokenSessionId, &SessionId, sizeof(SessionId), &rcb));
    
                    if (err == NOERROR)
                    {
                        PWSTR szSid;
    
                        err = BOOL_TO_ERROR(ConvertSidToStringSid(AppConainer->TokenAppContainer, &szSid));
    
                        if (err == NOERROR)
                        {
                            static const WCHAR fmt[] = L"\\\\?\\pipe\\Sessions\\%d\\AppContainerNamedObjects\\%s\\%s";
    
                            rcb = (1 + _scwprintf(fmt, SessionId, szSid, PipeName)) * sizeof(WCHAR);
    
                            if (cb < rcb)
                            {
                                cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
                            }
    
                            _swprintf(sz, fmt, SessionId, szSid, PipeName);
    
                            HANDLE hPipe = CreateNamedPipeW(sz,
                                PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, 
                                PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_WAIT, 
                                PIPE_UNLIMITED_INSTANCES, 0, 0, 0, &sa);
    
                            if (hPipe == INVALID_HANDLE_VALUE)
                            {
                                err = GetLastError();
                            }
                            else
                            {
                                *PipeHandle = hPipe;
                            }
    
                            LocalFree(szSid);
                        }
                    }
                    break;
                }
    
            } while (err == ERROR_INSUFFICIENT_BUFFER);
    
            CloseHandle(hToken);
        }
    
        LocalFree(sa.lpSecurityDescriptor);
    
        return err;
    }
    
    ULONG CreatePipeforUWP(OUT PHANDLE PipeHandle, PCWSTR PipeName, ULONG dwProcessId)
    {
        if (HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, 0, dwProcessId))
        {
            ULONG err = CreatePipeforUWP(PipeHandle, PipeName, hProcess);
            CloseHandle(hProcess);
            return err;
        }
        return GetLastError();
    }
    
    
    HANDLE hPipe;
    if (CreatePipeforUWP(&hPipe, L"MyPipe", *) == NOERROR)
    

    in client (UWP) app simply

    CreateFileW(L"\\\\?\\pipe\\local\\MyPipe", 
            FILE_GENERIC_READ|FILE_GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
    

    but for this server need know UWP session id (or process id) or assume that UWP run in same session with server. in general this is not nice.

    i be advice use RPC instead named pipes. here no any problems.

    desktop need use RpcServerRegisterIf3 and set SecurityDescriptor for interface for let UWP access it. say "D:P(A;;GA;;;WD)(A;;GA;;;AC)(A;;GA;;;S-1-15-2-2)S:(ML;;;;;LW)". and this fine work with UWP, for example server code

    ULONG InitRpcServer()
    {
        PSECURITY_DESCRIPTOR SecurityDescriptor;
    
        // generic all for SDDL_ALL_APP_PACKAGES + SDDL_EVERYONE
    
        ULONG dwError = BOOL_TO_ERROR(ConvertStringSecurityDescriptorToSecurityDescriptorW(
            L"D:P(A;;GA;;;WD)(A;;GA;;;AC)(A;;GA;;;S-1-15-2-2)S:(ML;;;;;LW)", SDDL_REVISION, &SecurityDescriptor, 0));
    
        if (dwError == ERROR_SUCCESS)
        {
            dwError = RpcServerRegisterIf3(hello_v1_0_s_ifspec,
                NULL, NULL, RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH,
                RPC_C_LISTEN_MAX_CALLS_DEFAULT, 0x10000, 0, SecurityDescriptor);
    
            if (dwError == RPC_S_OK)
            {
                dwError = RpcServerUseProtseqEpW(
                    (RPC_WSTR)L"ncalrpc",
                    RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
                    (RPC_WSTR)L"myname",
                    SecurityDescriptor);
    
                if (dwError == RPC_S_OK)
                {
                    dwError = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE);
                }
            }
    
            LocalFree(SecurityDescriptor);
        }
    
        return dwError;
    }
    

    and client only need

    RpcBindingFromStringBinding((RPC_WSTR)L"ncalrpc:[myname]", &IDL_handle)
    
    0 讨论(0)
  • 2020-12-20 11:11

    According to this page

    Pipes are only supported within an app-container; ie, from one UWP process to another UWP process that's part of the same app. Also, named pipes must use the syntax ".\pipe\LOCAL" for the pipe name.

    0 讨论(0)
提交回复
热议问题