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
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)
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.