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