/// <summary>
 ///  The DsrAddressToSiteNamesW method Supported in windows_2000_server,
 ///  windows_xp, windows_server_2003, windows_vista,  windows_server_2008,
 ///  windows_7, and windows_server_7. translates a list
 ///  of socket addresses into their corresponding site names.
 ///  For information about the mapping from socket address
 ///  to subnet/site name.
 ///  Opnum: 33 
 /// </summary>
 /// <param name="computerName">
 ///  The custom RPC binding handle that represents
 ///  the connection to a domain controller.
 /// </param>
 /// <param name="entryCount">
 ///  The number of socket addresses specified in SocketAddresses.
 ///  The maximum value for EntryCount is 32000.To avoid
 ///  large memory allocations, the number of 32,000 was
 ///  chosen as a reasonable limit for the maximum number
 ///  of socket addresses that this method accepts.
 /// </param>
 /// <param name="socketAddresses">
 ///  An array of NL_SOCKET_ADDRESS structures 
 ///  that contains socket addresses to translate. The number
 ///  of addresses specified MUST be equal to EntryCount.
 /// </param>
 /// <param name="siteNames">
 ///  A pointer to an NL_SITE_NAME_ARRAY structure 
 ///  that contains a corresponding array of site names.
 ///  The number of entries returned is equal to EntryCount.
 ///  An entry is returned as NULL if the corresponding socket
 ///  address does not map to any site, or if the address
 ///  family of the socket address is not IPV4 or IPV6. The
 ///  mapping of IP addresses to sites is specified in [MS-ADTS].
 /// </param>
 /// <returns>
 /// The method returns 0x00000000 on success; 
 /// otherwise, it returns a nonzero error code.
 /// </returns>
 public NetApiStatus DsrAddressToSiteNamesW(
     string computerName,
     uint entryCount,
     _NL_SOCKET_ADDRESS[] socketAddresses,
     out _NL_SITE_NAME_ARRAY? siteNames)
 {
     return rpc.DsrAddressToSiteNamesW(
         computerName,
         entryCount,
         socketAddresses,
         out siteNames);
 }
        /// <summary>
        ///  The DsrAddressToSiteNamesW method Supported in windows_2000_server,
        ///  windows_xp, windows_server_2003, windows_vista,  windows_server_2008,
        ///  windows_7, and windows_server_7. translates a list
        ///  of socket addresses into their corresponding site names.
        ///  For information about the mapping from socket address
        ///  to subnet/site name, see [MS-ADTS] sections  and .
        ///  Opnum: 33 
        /// </summary>
        /// <param name="ComputerName">
        ///  The custom RPC binding handle (section) that represents
        ///  the connection to a domain controller.
        /// </param>
        /// <param name="EntryCount">
        ///  The number of socket addresses specified in SocketAddresses.
        ///  The maximum value for EntryCount is 32000.To avoid
        ///  large memory allocations, the number of 32,000 was
        ///  chosen as a reasonable limit for the maximum number
        ///  of socket addresses that this method accepts.
        /// </param>
        /// <param name="SocketAddresses">
        ///  An array of NL_SOCKET_ADDRESS structures (section )
        ///  that contains socket addresses to translate. The number
        ///  of addresses specified MUST be equal to EntryCount.
        /// </param>
        /// <param name="SiteNames">
        ///  A pointer to an NL_SITE_NAME_ARRAY structure (section
        ///  ) that contains a corresponding array of site names.
        ///  The number of entries returned is equal to EntryCount.
        ///  An entry is returned as NULL if the corresponding socket
        ///  address does not map to any site, or if the address
        ///  family of the socket address is not IPV4 or IPV6. The
        ///  mapping of IP addresses to sites is specified in [MS-ADTS]
        ///  section.
        /// </param>
        public NetApiStatus DsrAddressToSiteNamesW(
            string ComputerName,
            uint EntryCount,
            _NL_SOCKET_ADDRESS[] SocketAddresses,
            out _NL_SITE_NAME_ARRAY? SiteNames)
        {
            const ushort opnum = 33;

            byte[] requestStub;
            byte[] responseStub;
            Int3264[] paramList;
            int retVal;

            //_RetVal = NdrClientCall2(
            //  ( PMIDL_STUB_DESC  )&logon_StubDesc,
            //  (PFORMAT_STRING) &ms2Dnrpc__MIDL_ProcFormatString.Format[724],
            //  ( unsigned char * )&ComputerName);
            //return ( NET_API_STATUS  )_RetVal.Simple;

            SafeIntPtr pComputerName = Marshal.StringToHGlobalUni(ComputerName);
            SafeIntPtr pSocketAddresses = TypeMarshal.ToIntPtr(SocketAddresses);

            paramList = new Int3264[] {
                pComputerName,
                EntryCount,
                Marshal.ReadIntPtr(pSocketAddresses),
                IntPtr.Zero,
                0 // retVal
            };

            requestStub = RpceStubEncoder.ToBytes(
                     RpceStubHelper.GetPlatform(),
                    NrpcRpcStubFormatString.TypeFormatString,
                    new RpceStubExprEval[] { new RpceStubExprEval(logon__NETLOGON_DELTA_USERExprEval_0000) },
                    NrpcRpcStubFormatString.ProcFormatString,
                    NrpcRpcStubFormatString.ProcFormatStringOffsetTable[opnum],
                    true,
                    paramList);

            rpceClientTransport.Call(opnum, requestStub, rpceTimeout, out responseStub);

            using (RpceInt3264Collection outParamList = RpceStubDecoder.ToParamList(
                     RpceStubHelper.GetPlatform(),
                    NrpcRpcStubFormatString.TypeFormatString,
                    new RpceStubExprEval[] { new RpceStubExprEval(logon__NETLOGON_DELTA_USERExprEval_0000) },
                    NrpcRpcStubFormatString.ProcFormatString,
                    NrpcRpcStubFormatString.ProcFormatStringOffsetTable[opnum],
                    true,
                    responseStub,
                    paramList))
            {
                IntPtr pSiteNames = outParamList[3];
                pSiteNames = Marshal.ReadIntPtr(pSiteNames);
                SiteNames = TypeMarshal.ToNullableStruct<_NL_SITE_NAME_ARRAY>(pSiteNames);

                retVal = outParamList[4].ToInt32();
            }

            pComputerName.Dispose();
            pSocketAddresses.Dispose();

            return (NetApiStatus)retVal;
        }
        public _NL_SOCKET_ADDRESS CreateNlSocketAddress(IPEndPoint sockaddr)
        {
            _NL_SOCKET_ADDRESS nlSocketAddress = new _NL_SOCKET_ADDRESS();

            if (sockaddr == null)
            {
                nlSocketAddress.lpSockaddr = null;
                nlSocketAddress.iSockaddrLength = 0;
            }
            else
            {
                switch (sockaddr.AddressFamily)
                {
                    case AddressFamily.InterNetwork:
                        nlSocketAddress.lpSockaddr = ArrayUtility.ConcatenateArrays(
                            BitConverter.GetBytes((ushort)(AddressFamily.InterNetwork)),
                            BitConverter.GetBytes((ushort)sockaddr.Port),
                            sockaddr.Address.GetAddressBytes(),
                            new byte[8]); // 8-bytes padding, ignored by the server.
                        break;

                    case AddressFamily.InterNetworkV6:
                        nlSocketAddress.lpSockaddr = ArrayUtility.ConcatenateArrays(
                            BitConverter.GetBytes((ushort)(AddressFamily.InterNetworkV6)),
                            BitConverter.GetBytes((ushort)sockaddr.Port),
                            new byte[4], //FlowInfo (4 bytes): Flow information.
                            //This field is not currently used by the protocol.
                            //The field MUST be set to zero and MUST be ignored on receipt.
                            sockaddr.Address.GetAddressBytes(),
                            BitConverter.GetBytes((uint)sockaddr.Address.ScopeId));
                        break;

                    default:
                        throw new ArgumentException("sockaddr is neither IPv4 nor IPv6.", "sockaddr");
                }
                nlSocketAddress.iSockaddrLength = (uint)nlSocketAddress.lpSockaddr.Length;
            }

            return nlSocketAddress;
        }