private static DeviceInformationFoundEventArgs GetDeviceInformationFoundEventArgs(int requestId, IntPtr deviceInfoHandle)
        {
            IntPtr name, specVersion, deviceId, dataModelVersion;

            int ret = Interop.IoTConnectivity.Client.DeviceInformation.GetProperty(deviceInfoHandle, (int)Interop.IoTConnectivity.Client.DeviceInformation.Property.Name, out name);

            if (ret != (int)IoTConnectivityError.None)
            {
                Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get name");
                return(null);
            }

            ret = Interop.IoTConnectivity.Client.DeviceInformation.GetProperty(deviceInfoHandle, (int)Interop.IoTConnectivity.Client.DeviceInformation.Property.SpecVersion, out specVersion);
            if (ret != (int)IoTConnectivityError.None)
            {
                Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get spec version");
                return(null);
            }

            ret = Interop.IoTConnectivity.Client.DeviceInformation.GetProperty(deviceInfoHandle, (int)Interop.IoTConnectivity.Client.DeviceInformation.Property.Id, out deviceId);
            if (ret != (int)IoTConnectivityError.None)
            {
                Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get device id");
                return(null);
            }

            ret = Interop.IoTConnectivity.Client.DeviceInformation.GetProperty(deviceInfoHandle, (int)Interop.IoTConnectivity.Client.DeviceInformation.Property.DataModelVersion, out dataModelVersion);
            if (ret != (int)IoTConnectivityError.None)
            {
                Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get data model version");
                return(null);
            }

            DeviceInformationFoundEventArgs e = new DeviceInformationFoundEventArgs()
            {
                RequestId        = requestId,
                EventContinue    = true,
                Name             = (name != IntPtr.Zero) ? Marshal.PtrToStringAnsi(name) : string.Empty,
                SpecVersion      = (specVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(specVersion) : string.Empty,
                DeviceId         = (deviceId != IntPtr.Zero) ? Marshal.PtrToStringAnsi(deviceId) : string.Empty,
                DataModelVersion = (dataModelVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(dataModelVersion) : string.Empty
            };

            return(e);
        }
        /// <summary>
        /// Starts finding the device information of remote server.
        /// </summary>
        /// <since_tizen> 3 </since_tizen>
        /// <remarks>
        /// <para>Requests server for device information.
        /// If succeeded, <see cref="DeviceInformationFound"/> event handler will be triggered with information of the device.</para>
        /// <para><paramref name="hostAddress" /> could be <see cref="MulticastAddress"/> for the IPv4 multicast.</para>
        /// </remarks>
        /// <privilege>http://tizen.org/privilege/internet</privilege>
        /// <privlevel>public</privlevel>
        /// <param name="hostAddress">The host address of the remote server.</param>
        /// <param name="query">The query specified as a filter for founding resources.</param>
        /// <returns>RequestId - An identifier for this request.</returns>
        /// <feature>http://tizen.org/feature/iot.ocf</feature>
        /// <pre>Initialize() should be called to initialize.</pre>
        /// <post>
        /// <see cref="DeviceInformationFound" /> event handler will be invoked.
        /// </post>
        /// <seealso cref="IoTConnectivityServerManager.SetDeviceName(string)"/>
        /// <seealso cref="DeviceInformationFound"/>
        /// <seealso cref="DeviceInformationFoundEventArgs"/>
        /// <seealso cref="TimeOut"/>
        /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported.</exception>
        /// <exception cref="InvalidOperationException">Thrown when the operation is invalid.</exception>
        /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have privilege to access.</exception>
        /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory.</exception>
        /// <example><code><![CDATA[
        /// EventHandler<DeviceInformationFoundEventArgs> handler = (sender, e) => {
        ///     Console.Log("Device information found, id : " + e.RequestId + ", name : " + e.Name);
        /// }
        /// EventHandler<FindingErrorOccurredEventArgs> errorHandler = (sender, e) => {
        ///     Console.Log("Found error :" + e.Error.Message);
        /// }
        /// IoTConnectivityClientManager.DeviceInformationFound += handler;
        /// IoTConnectivityClientManager.FindingErrorOccurred += errorHandler;
        /// // Do not forget to remove these event handlers when they are not required any more.
        /// int id = IoTConnectivityClientManager.StartFindingDeviceInformation(IoTConnectivityClientManager.MulticastAddress);
        /// ]]></code></example>
        public static int StartFindingDeviceInformation(string hostAddress, ResourceQuery query = null)
        {
            Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType connectivityType = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ip;

            IntPtr id = IntPtr.Zero;

            lock (s_deviceInformationCallbacksMap)
            {
                id = (IntPtr)s_requestId++;
            }
            s_deviceInformationCallbacksMap[id] = (IntPtr deviceInfoHandle, int result, IntPtr userData) =>
            {
                if (DeviceInformationFound == null)
                {
                    return(false);
                }

                int requestId = (int)userData;
                if (result == (int)IoTConnectivityError.None)
                {
                    if (deviceInfoHandle != IntPtr.Zero)
                    {
                        DeviceInformationFoundEventArgs e = GetDeviceInformationFoundEventArgs(requestId, deviceInfoHandle);
                        if (e == null)
                        {
                            Log.Error(IoTConnectivityErrorFactory.LogTag, "Can't get DeviceInformationFoundEventArgs");
                            return(true);
                        }
                        DeviceInformationFound?.Invoke(null, e);
                        Log.Info(IoTConnectivityErrorFactory.LogTag, "e.EventContinue : " + e.EventContinue);
                        return(e.EventContinue);
                    }
                    else
                    {
                        Log.Error(IoTConnectivityErrorFactory.LogTag, "Handle is null");
                    }
                }
                else
                {
                    FindingErrorOccurredEventArgs e = GetFindingErrorOccurredEventArgs(requestId, result);
                    FindingErrorOccurred?.Invoke(null, e);

                    lock (s_deviceInformationCallbacksMap)
                    {
                        s_deviceInformationCallbacksMap.Remove(id);
                    }
                }
                return(true);
            };

            IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
            int    errorCode   = Interop.IoTConnectivity.Client.DeviceInformation.Find(hostAddress, (int)connectivityType, queryHandle, s_deviceInformationCallbacksMap[id], id);

            if (errorCode != (int)IoTConnectivityError.None)
            {
                Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get device information");
                lock (s_deviceInformationCallbacksMap)
                {
                    s_deviceInformationCallbacksMap.Remove(id);
                }
                throw IoTConnectivityErrorFactory.GetException(errorCode);
            }

            return((int)id);
        }