You cannot impersonate a pipe until you have read from it. Even a write call doesn’t work. So a service has to wait for a dummy client write call until it can check the client’s token.

The following codes shows how multi instance pipe server could look like. Be aware that I wrote this to show how it can be done and not for a simple copy&paste.

//necessary units
uses JwaWindows, …, JwsclToken, JwsclUtils, JwsclComUtils, JwsclLogging, SvcMgr;

{checks ReadFile and WriteFile result but ignores overlapped error result}
function CheckPipe(const Value : Boolean) : Boolean;
begin
  result := (Value )
      or (not Value and (GetLastError() = ERROR_IO_PENDING));
end;

var
  ServiceStopEvent : THandle; //define a stop event for the service
  Stopped : Boolean = false;

procedureServiceExecute
var
  Log : IJwLogClient;

  ProtocolVersion,
  WaitResult : DWORD;
  Msg : TMsg;
  OvLapped : OVERLAPPED;
  PipeToken : TJwSecurityToken;
begin
  //JWSCL logging
  Log := uLogging.LogServer.Connect(etMethod,ClassName,
          ‘ServiceExecute’,‘MainUnit.pas’,);

  hPipe := CreateNamedPipe(‘\\.\pipe\PipeName’,
        PIPE_ACCESS_DUPLEX or FILE_FLAG_OVERLAPPED,
        PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 0, 0, 0, nil);

  //check hPipe here…TODO for the reader

  ZeroMemory(@OvLapped, sizeof(OvLapped));
  OvLapped.hEvent := CreateEvent(nil, false, false, nil);
  //auto CloseHandle
  TJwAutoPointer.Wrap(OvLapped.hEvent);

  Stopped := false;
  //for services we use this msg friendly approach
  repeat //1.
     ConnectNamedPipe(Pipe, @OvLapped);

     repeat //2.
       ServiceThread.ProcessRequests(False);
       WaitResult := JwMsgWaitForMultipleObjects([ServiceStopEvent, OvLapped.hEvent], false, INFINITE, QS_ALLINPUT);

       case WaitResult of
          WAIT_OBJECT_0 + 1 :  ResetEvent(OvLapped.hEvent);
          WAIT_OBJECT_0 + 2 :  PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE); //tag message as read, so waitfor does not return next time
       else
          //another problem
       end;
     until WaitResult <> WAIT_OBJECT_0 + 2; //2.

     if WaitResult = WAIT_OBJECT_0 +1 then //connected
     begin
       //read dummy data or e.g. Protocol version of client
       if not CheckPipe(ReadFile(Pipe, @ProtocolVersion, sizeof(ProtocolVersion) ,nil, @OvLapped)) then
         //uhh error
       else
       begin
         //JWSCL JwsclUtils.pas implements this more convenient wait function
         if JwWaitForMultipleObjects([ServiceStopEvent, OvLapped.hEvent], false,
                TIMEOUT) = WAIT_OBJECT_0 +1 then
         begin
            try
              //now we can get the client’s token – may throw exception if it fails!
              TJwSecurityToken.ImpersonateNamedPipeClient(Pipe);

              try
                PipeToken := TJwSecurityToken.CreateTokenByThread(0, MAXIMUM_ALLOWED, true);
              finally
                TJwSecurityToken.RevertToSelf;
              end;
              //……. go on with what you want
            on E : Exception do
            begin
              Log.Exception(E);
            end;
         end
         else
           Log.Log(‘Read for protocol version failed.’);
       end;
     end;

     DisconnectNamedPipe(Pipe);
  until Stopped; //1. – the one who signales ServiceStopEvent, must also set this boolean value to true

  CloseHandle(Pipe);
end;