2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 using System.Collections.Generic;
20 using System.Runtime.InteropServices;
22 namespace Tizen.Applications
25 /// Represents the control message to exchange between applications.
29 /// public class AppControlExample : UIApplication
32 /// protected override void OnAppControlReceived(AppControlReceivedEventArgs e)
34 /// AppControl appControl = new AppControl();
35 /// appControl.ApplicationId = "org.tizen.calculator";
36 /// AppControl.SendLaunchRequest(appControl, (launchRequest, replyRequest, result) => {
43 public class AppControl
45 private const string LogTag = "Tizen.Applications";
47 private static Dictionary<int, Interop.AppControl.ReplyCallback> s_replyNativeCallbackMaps = new Dictionary<int, Interop.AppControl.ReplyCallback>();
48 private static int s_replyNativeCallbackId = 0;
50 private readonly SafeAppControlHandle _handle;
52 private string _operation = null;
53 private string _mime = null;
54 private string _uri = null;
55 private string _category = null;
56 private string _applicationId = null;
57 private ExtraDataCollection _extraData = null;
60 /// Initializes the instance of the AppControl class.
62 /// <exception cref="InvalidOperationException">Thrown when failed to create the AppControl handle.</exception>
65 Interop.AppControl.ErrorCode err = Interop.AppControl.Create(out _handle);
66 if (err != Interop.AppControl.ErrorCode.None)
68 throw new InvalidOperationException("Failed to create the appcontrol handle. Err = " + err);
73 /// Initializes the instance of the AppControl class with a parameter.
75 /// <param name="enableAppStartedResultEvent">The flag value to receive an additional launch result event on the launch request.</param>
76 /// <exception cref="InvalidOperationException">Thrown when failed to create the AppControl handle.</exception>
77 public AppControl(bool enableAppStartedResultEvent)
79 Interop.AppControl.ErrorCode err = Interop.AppControl.Create(out _handle);
80 if (err != Interop.AppControl.ErrorCode.None)
82 throw new InvalidOperationException("Failed to create the appcontrol handle. Err = " + err);
85 if (enableAppStartedResultEvent)
87 err = Interop.AppControl.EnableAppStartedResultEvent(_handle);
88 if (err != Interop.AppControl.ErrorCode.None)
90 throw new InvalidOperationException("Failed to set EnableAppStartedResultEvent");
96 /// Initializes the instance of the AppControl class with the SafeAppControlHandle.
98 /// <param name="handle"></param>
99 public AppControl(SafeAppControlHandle handle)
103 throw new ArgumentNullException("handle");
106 Interop.AppControl.ErrorCode err = Interop.AppControl.DangerousClone(out _handle, handle.DangerousGetHandle());
107 if (err != Interop.AppControl.ErrorCode.None)
109 throw new InvalidOperationException("Failed to clone the appcontrol handle. Err = " + err);
113 private AppControl(IntPtr handle)
115 Interop.AppControl.ErrorCode err = Interop.AppControl.DangerousClone(out _handle, handle);
116 if (err != Interop.AppControl.ErrorCode.None)
118 throw new InvalidOperationException("Failed to clone the appcontrol handle. Err = " + err);
122 #region Public Properties
125 /// Gets the SafeAppControlHandle instance.
127 public SafeAppControlHandle SafeAppControlHandle
136 /// Gets and sets the operation to be performed.
139 /// The operation is the mandatory information for the launch request. If the operation is not specified,
140 /// AppControlOperations.Default is used for the launch request. If the operation is AppControlOperations.Default,
141 /// the package information is mandatory to explicitly launch the application.
142 /// (if the operation is null for setter, it clears the previous value.)
146 /// AppControl appControl = new AppControl();
147 /// appControl.Operation = AppControlOperations.Default;
148 /// Log.Debug(LogTag, "Operation: " + appControl.Operation);
151 public string Operation
155 if (String.IsNullOrEmpty(_operation))
157 Interop.AppControl.ErrorCode err = Interop.AppControl.GetOperation(_handle, out _operation);
158 if (err != Interop.AppControl.ErrorCode.None)
160 Log.Warn(LogTag, "Failed to get the operation from the appcontrol. Err = " + err);
167 Interop.AppControl.ErrorCode err = Interop.AppControl.SetOperation(_handle, value);
168 if (err == Interop.AppControl.ErrorCode.None)
174 Log.Warn(LogTag, "Failed to set the operation to the appcontrol. Err = " + err);
180 /// Gets and sets the explicit MIME type of the data.
183 /// (if the mime is null for setter, it clears the previous value.)
187 /// AppControl appControl = new AppControl();
188 /// appControl.Mime = "image/jpg";
189 /// Log.Debug(LogTag, "Mime: " + appControl.Mime);
196 if (String.IsNullOrEmpty(_mime))
198 Interop.AppControl.ErrorCode err = Interop.AppControl.GetMime(_handle, out _mime);
199 if (err != Interop.AppControl.ErrorCode.None)
201 Log.Warn(LogTag, "Failed to get the mime from the appcontrol. Err = " + err);
208 Interop.AppControl.ErrorCode err = Interop.AppControl.SetMime(_handle, value);
209 if (err == Interop.AppControl.ErrorCode.None)
215 Log.Warn(LogTag, "Failed to set the mime to the appcontrol. Err = " + err);
221 /// Gets and sets the URI of the data.
224 /// Since Tizen 2.4, if the parameter 'uri' is started with 'file://' and
225 /// it is a regular file in this application's data path, which can be obtained
226 /// by property DataPath in ApplicationInfo class,
227 /// it will be shared to the callee application.
228 /// Framework will grant a temporary permission to the callee application for this file and
229 /// revoke it when the callee application is terminated.
230 /// The callee application can just read it.
231 /// (if the uri is null for setter, it clears the previous value.)
235 /// public class AppControlExample : UIApplication
238 /// protected override void OnAppControlReceived(AppControlReceivedEventArgs e)
241 /// AppControl appControl = new AppControl();
242 /// appContrl.Uri = this.ApplicationInfo.DataPath + "image.jpg";
243 /// Log.Debug(LogTag, "Set Uri: " + appControl.Uri);
252 if (String.IsNullOrEmpty(_uri))
254 Interop.AppControl.ErrorCode err = Interop.AppControl.GetUri(_handle, out _uri);
255 if (err != Interop.AppControl.ErrorCode.None)
257 Log.Warn(LogTag, "Failed to get the uri from the appcontrol. Err = " + err);
264 Interop.AppControl.ErrorCode err = Interop.AppControl.SetUri(_handle, value);
265 if (err == Interop.AppControl.ErrorCode.None)
271 Log.Warn(LogTag, "Failed to set the uri to the appcontrol. Err = " + err);
277 /// Gets and sets the explicit category.
280 /// (if the category is null for setter, it clears the previous value.)
282 public string Category
286 if (String.IsNullOrEmpty(_category))
288 Interop.AppControl.ErrorCode err = Interop.AppControl.GetCategory(_handle, out _category);
289 if (err != Interop.AppControl.ErrorCode.None)
291 Log.Warn(LogTag, "Failed to get the category from the appcontrol. Err = " + err);
298 Interop.AppControl.ErrorCode err = Interop.AppControl.SetCategory(_handle, value);
299 if (err == Interop.AppControl.ErrorCode.None)
305 Log.Warn(LogTag, "Failed to set the category to the appcontrol. Err = " + err);
311 /// Gets and sets the application ID to explicitly launch.
314 /// (if the application ID is null for setter, it clears the previous value.)
318 /// AppControl appControl = new AppControl();
319 /// appControl.ApplicationId = "org.tizen.calculator";
320 /// Log.Debug(LogTag, "ApplicationId: " + appControl.ApplicationId);
323 public string ApplicationId
327 if (String.IsNullOrEmpty(_applicationId))
329 Interop.AppControl.ErrorCode err = Interop.AppControl.GetAppId(_handle, out _applicationId);
330 if (err != Interop.AppControl.ErrorCode.None)
332 Log.Warn(LogTag, "Failed to get the application id from the AppControl. Err = " + err);
335 return _applicationId;
339 Interop.AppControl.ErrorCode err = Interop.AppControl.SetAppId(_handle, value);
340 if (err == Interop.AppControl.ErrorCode.None)
342 _applicationId = value;
346 Log.Warn(LogTag, "Failed to set the application id to the AppControl. Err = " + err);
352 /// Gets and sets the launch mode of the application.
355 /// Although, LaunchMode were set as AppControlLaunchMode.Group, the
356 /// callee application would be launched as a single mode
357 /// if the manifest file of callee application defined the launch mode as "single".
358 /// This property can just set the preference of the caller application to launch an application.
359 /// Sub-applications, which were launched as a group mode always have own process.
360 /// Since Tizen 3.0, if launch mode is not set in the caller application control,
361 /// this property returns the AppControlLaunchMode.Single launch mode.
365 /// AppControl appControl = new AppControl();
366 /// appControl.LaunchMode = AppControlLaunchMode.Group;
369 public AppControlLaunchMode LaunchMode
374 Interop.AppControl.ErrorCode err = Interop.AppControl.GetLaunchMode(_handle, out value);
375 if (err != Interop.AppControl.ErrorCode.None)
377 Log.Warn(LogTag, "Failed to get the LaunchMode from the AppControl. Err = " + err);
379 return (AppControlLaunchMode)value;
383 Interop.AppControl.ErrorCode err = Interop.AppControl.SetLaunchMode(_handle, (int)value);
384 if (err != Interop.AppControl.ErrorCode.None)
386 Log.Warn(LogTag, "Failed to set the LaunchMode to the AppControl. Err = " + err);
392 /// Gets the collection of the extra data.
395 /// Extra data for communication between AppControls.
399 /// AppControl appControl = new AppControl();
400 /// appControl.ExtraData.Add("key", "value");
404 public ExtraDataCollection ExtraData
408 if (_extraData == null)
409 _extraData = new ExtraDataCollection(_handle);
414 #endregion // Public Properties
417 /// Retrieves all applications that can be launched to handle the given app_control request.
419 /// <param name="control">The AppControl.</param>
420 /// <returns>ApplicationIds.</returns>
421 /// <exception cref="InvalidOperationException">Thrown when failed because of an invalid parameter.</exception>
424 /// IEnumerable<string> applicationIds = AppControl.GetMatchedApplicationIds(control);
425 /// if (applicationIds != null)
427 /// foreach (string id in applicationIds)
434 public static IEnumerable<string> GetMatchedApplicationIds(AppControl control)
438 throw new ArgumentNullException("control");
441 List<string> ids = new List<string>();
442 Interop.AppControl.AppMatchedCallback callback = (handle, applicationId, userData) =>
444 if (applicationId == null)
449 ids.Add(applicationId);
453 Interop.AppControl.ErrorCode err = Interop.AppControl.ForeachAppMatched(control._handle, callback, IntPtr.Zero);
454 if (err != Interop.AppControl.ErrorCode.None)
456 throw new InvalidOperationException("Failed to get matched application ids. err = " + err);
463 /// Sends the launch request.
466 /// The operation is mandatory information for the launch request.
467 /// If the operation is not specified, AppControlOperations.Default is used by default.
468 /// If the operation is AppControlOperations.Default, the application ID is mandatory to explicitly launch the application. \n
469 /// Since Tizen 2.4, the launch request of the service application over out of packages is restricted by the platform.
470 /// Also, implicit launch requests are NOT delivered to service applications since 2.4.
471 /// To launch a service application, an explicit launch request with the application ID given by property ApplicationId MUST be sent.
473 /// <param name="launchRequest">The AppControl.</param>
474 /// <exception cref="ArgumentNullException">Thrown when failed because of a null argument.</exception>
475 /// <exception cref="InvalidOperationException">Thrown when failed because of an invalid operation.</exception>
476 /// <exception cref="TimeoutException">Thrown when failed because of timeout.</exception>
477 /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
480 /// AppControl appControl = new AppControl();
481 /// appControl.ApplicationId = "org.tizen.calculator";
482 /// AppControl.SendLaunchRequest(appControl);
485 public static void SendLaunchRequest(AppControl launchRequest)
487 SendLaunchRequest(launchRequest, null);
491 /// Sends the launch request.
494 /// The operation is mandatory information for the launch request.
495 /// If the operation is not specified, AppControlOperations.Default is used by default.
496 /// If the operation is AppControlOperations.Default, the application ID is mandatory to explicitly launch the application. \n
497 /// Since Tizen 2.4, the launch request of the service application over out of packages is restricted by the platform.
498 /// Also, implicit launch requests are NOT delivered to service applications since 2.4.
499 /// To launch a service application, an explicit launch request with the application ID given by property ApplicationId MUST be sent.
501 /// <param name="launchRequest">The AppControl.</param>
502 /// <param name="replyAfterLaunching">The callback function to be called when the reply is delivered.</param>
503 /// <exception cref="ArgumentException">Thrown when failed because of the argument is invalid.</exception>
504 /// <exception cref="Exceptions.AppNotFoundException">Thrown when the application to run is not found.</exception>
505 /// <exception cref="Exceptions.LaunchFailedException">Thrown when the request failed to launch the application.</exception>
506 /// <exception cref="Exceptions.LaunchRejectedException">Thrown when the launch request is rejected.</exception>
507 /// <exception cref="Exceptions.OutOfMemoryException">Thrown when the memory is insufficient.</exception>
508 /// <exception cref="Exceptions.PermissionDeniedException">Thrown when the permission is denied.</exception>
509 /// <exception cref="TimeoutException">Thrown when failed because of timeout.</exception>
510 /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
513 /// AppControl appControl = new AppControl();
514 /// appControl.ApplicationId = "org.tizen.calculator";
515 /// AppControl.SendLaunchRequest(appControl, (launchRequest, replyRequest, result) => {
520 public static void SendLaunchRequest(AppControl launchRequest, AppControlReplyCallback replyAfterLaunching)
522 if (launchRequest == null)
524 throw new ArgumentNullException("launchRequest");
527 Interop.AppControl.ErrorCode err;
529 if (replyAfterLaunching != null)
532 lock (s_replyNativeCallbackMaps)
534 id = s_replyNativeCallbackId++;
535 s_replyNativeCallbackMaps[id] = (launchRequestHandle, replyRequestHandle, result, userData) =>
537 if (replyAfterLaunching != null)
539 Log.Debug(LogTag, "Reply Callback is launched");
540 replyAfterLaunching(new AppControl(launchRequestHandle), new AppControl(replyRequestHandle), (AppControlReplyResult)result);
541 if (result != Interop.AppControl.AppStartedStatus)
543 lock (s_replyNativeCallbackMaps)
545 s_replyNativeCallbackMaps.Remove(id);
551 err = Interop.AppControl.SendLaunchRequest(launchRequest._handle, s_replyNativeCallbackMaps[id], IntPtr.Zero);
555 err = Interop.AppControl.SendLaunchRequest(launchRequest._handle, null, IntPtr.Zero);
558 if (err != Interop.AppControl.ErrorCode.None)
562 case Interop.AppControl.ErrorCode.InvalidParameter:
563 throw new ArgumentException("Invalid Arguments");
564 case Interop.AppControl.ErrorCode.TimedOut:
565 throw new TimeoutException("Timed out");
566 case Interop.AppControl.ErrorCode.OutOfMemory:
567 throw new Exceptions.OutOfMemoryException("Out-of-memory");
568 case Interop.AppControl.ErrorCode.AppNotFound:
569 throw new Exceptions.AppNotFoundException("App not found");
570 case Interop.AppControl.ErrorCode.LaunchRejected:
571 throw new Exceptions.LaunchRejectedException("Launch rejected");
572 case Interop.AppControl.ErrorCode.LaunchFailed:
573 throw new Exceptions.LaunchFailedException("Launch failed");
574 case Interop.AppControl.ErrorCode.PermissionDenied:
575 throw new Exceptions.PermissionDeniedException("Permission denied");
578 throw new Exceptions.LaunchRejectedException("Launch rejected");
584 /// Sends the terminate request to the application that is launched by AppControl.
587 /// You are not allowed to terminate other general applications using this API.
588 /// This API can be used to terminate sub-applications, which were launched as a group mode by the caller application.
589 /// Once the callee application is being terminated by this API,
590 /// other applications, which were launched by the callee application as a group mode will be terminated as well.
592 /// <param name="terminateRequest">The AppControl.</param>
593 /// <exception cref="ArgumentException">Thrown when failed because of the argument is invalid.</exception>
594 /// <exception cref="InvalidOperationException">Thrown when failed because of an invalid operation.</exception>
595 /// <exception cref="TimeoutException">Thrown when failed because of timeout.</exception>
598 /// AppControl terminateRequest = new AppControl();
599 /// terminateRequest.ApplicationId = "org.tizen.calculator";
600 /// AppControl.SendTerminateRequest(terminateRequest);
603 public static void SendTerminateRequest(AppControl terminateRequest)
605 if (terminateRequest == null)
607 throw new ArgumentNullException("terminateRequest");
609 Interop.AppControl.ErrorCode err;
611 err = Interop.AppControl.SendTerminateRequest(terminateRequest._handle);
613 if (err != Interop.AppControl.ErrorCode.None)
617 case Interop.AppControl.ErrorCode.InvalidParameter:
618 throw new ArgumentException("Invalid Arguments");
619 case Interop.AppControl.ErrorCode.TimedOut:
620 throw new TimeoutException("Timed out");
622 throw new InvalidOperationException("Error = " + err);
628 /// Class for extra data.
630 public class ExtraDataCollection
632 private readonly SafeAppControlHandle _handle;
634 internal ExtraDataCollection(SafeAppControlHandle handle)
643 /// The function replaces any existing value for the given key.
645 /// <param name="key">The name of the extra data.</param>
646 /// <param name="value">The value associated with the given key.</param>
647 /// <exception cref="ArgumentNullException">Thrown when a key or a value is a zero-length string.</exception>
648 /// <exception cref="ArgumentException">Thrown when the application tries to use the same key with the system-defined key.</exception>
651 /// AppControl appControl = new AppControl();
652 /// appControl.ExtraData.Add("myKey", "myValue");
655 public void Add(string key, string value)
657 if (string.IsNullOrEmpty(key))
659 throw new ArgumentNullException("key");
661 if (string.IsNullOrEmpty(value))
663 throw new ArgumentNullException("value");
665 Interop.AppControl.ErrorCode err = Interop.AppControl.AddExtraData(_handle, key, value);
666 if (err != Interop.AppControl.ErrorCode.None)
670 case Interop.AppControl.ErrorCode.InvalidParameter:
671 throw new ArgumentException("Invalid parameter: key or value is a zero-length string");
672 case Interop.AppControl.ErrorCode.KeyRejected:
673 throw new ArgumentException("Key is rejected: the key is system-defined key.");
675 throw new InvalidOperationException("Error = " + err);
684 /// The function replaces any existing value for the given key.
686 /// <param name="key">The name of the extra data.</param>
687 /// <param name="value">The value associated with the given key.</param>
688 /// <exception cref="ArgumentNullException">Thrown when key or value is a zero-length string.</exception>
689 /// <exception cref="ArgumentException">Thrown when the application tries to use the same key with the system-defined key.</exception>
692 /// AppControl appControl = new AppControl();
693 /// string[] myValues = new string[] { "first", "second", "third" };
694 /// appControl.ExtraData.Add("myKey", myValues);
697 public void Add(string key, IEnumerable<string> value)
699 if (string.IsNullOrEmpty(key))
701 throw new ArgumentNullException("key");
705 throw new ArgumentNullException("value");
707 string[] valueArray = value.ToArray();
708 Interop.AppControl.ErrorCode err = Interop.AppControl.AddExtraDataArray(_handle, key, valueArray, valueArray.Length);
709 if (err != Interop.AppControl.ErrorCode.None)
713 case Interop.AppControl.ErrorCode.InvalidParameter:
714 throw new ArgumentException("Invalid parameter: key or value is a zero-length string");
715 case Interop.AppControl.ErrorCode.KeyRejected:
716 throw new ArgumentException("Key is rejected: the key is system-defined key.");
718 throw new InvalidOperationException("Error = " + err);
724 /// Gets the extra data.
726 /// <typeparam name="T">Only string and IEnumerable<string></typeparam>
727 /// <param name="key">The name of extra data.</param>
728 /// <returns>The value associated with the given key.</returns>
729 /// <exception cref="ArgumentNullException">Thrown when the key is an invalid parameter.</exception>
730 /// <exception cref="KeyNotFoundException">Thrown when the key is not found.</exception>
731 /// <exception cref="ArgumentException">Thrown when the key is rejected.</exception>
734 /// AppControl appControl = new AppControl();
735 /// string myValue = appControl.ExtraData.Get<string>("myKey");
738 public T Get<T>(string key)
740 object ret = Get(key);
745 /// Gets the extra data.
747 /// <param name="key">The name of extra data.</param>
748 /// <returns>The value associated with the given key.</returns>
749 /// <exception cref="ArgumentNullException">Thrown when the key is an invalid parameter.</exception>
750 /// <exception cref="KeyNotFoundException">Thrown when the key is not found.</exception>
751 /// <exception cref="ArgumentException">Thrown when the key is rejected.</exception>
754 /// AppControl appControl = new AppControl();
755 /// string myValue = appControl.ExtraData.Get("myKey") as string;
756 /// if (myValue != null)
762 public object Get(string key)
764 if (IsCollection(key))
766 return GetDataCollection(key);
775 /// Gets all keys in extra data.
777 /// <returns>The keys in the AppControl.</returns>
778 /// <exception cref="InvalidOperationException">Thrown when the key is an invalid parameter.</exception>
781 /// AppControl appControl = new AppControl();
782 /// IEnumerable<string> keys = appControl.GetKeys();
783 /// if (keys != null)
785 /// foreach (string key in keys)
792 public IEnumerable<string> GetKeys()
794 List<string> keys = new List<string>();
795 Interop.AppControl.ExtraDataCallback callback = (handle, key, userData) =>
806 Interop.AppControl.ErrorCode err = Interop.AppControl.ForeachExtraData(_handle, callback, IntPtr.Zero);
807 if (err != Interop.AppControl.ErrorCode.None)
809 throw new InvalidOperationException("Failed to get keys. err = " + err);
816 /// Tries getting the extra data.
818 /// <param name="key">The name of extra data.</param>
819 /// <param name="value">The value associated with the given key.</param>
820 /// <returns>The result whether getting the value is done.</returns>
821 /// <exception cref="ArgumentNullException">Thrown when the key is an invalid parameter.</exception>
822 /// <exception cref="KeyNotFoundException">Thrown when the key is not found.</exception>
823 /// <exception cref="ArgumentException">Thrown when the key is rejected.</exception>
826 /// AppControl appControl = new AppControl();
827 /// string myValue = string.Empty;
828 /// bool result = appControl.ExtraData.TryGet("myKey", out myValue);
829 /// if (result != null)
835 public bool TryGet(string key, out string value)
837 if (string.IsNullOrEmpty(key))
839 throw new ArgumentNullException("key");
841 Interop.AppControl.GetExtraData(_handle, key, out value);
848 value = default(string);
854 /// Tries getting the extra data.
856 /// <param name="key">The name of extra data.</param>
857 /// <param name="value">The value associated with the given key.</param>
858 /// <returns>The result whether getting the value is done.</returns>
859 /// <exception cref="ArgumentNullException">Thrown when the key is an invalid parameter.</exception>
860 /// <exception cref="KeyNotFoundException">Thrown when the key is not found.</exception>
861 /// <exception cref="ArgumentException">Thrown when the key is rejected.</exception>
864 /// AppControl appControl = new AppControl();
865 /// IEnumerable<string> myValue = null;
866 /// bool result = appControl.ExtraData.TryGet("myKey", out myValue);
869 /// foreach (string value in myValue)
876 public bool TryGet(string key, out IEnumerable<string> value)
878 if (string.IsNullOrEmpty(key))
880 throw new ArgumentNullException("key");
882 IntPtr valuePtr = IntPtr.Zero;
884 Interop.AppControl.ErrorCode err = Interop.AppControl.GetExtraDataArray(_handle, key, out valuePtr, out len);
885 if (err == Interop.AppControl.ErrorCode.None && valuePtr != IntPtr.Zero)
887 List<string> stringList = new List<string>();
888 for (int i = 0; i < len; ++i)
890 IntPtr charArr = Marshal.ReadIntPtr(valuePtr, IntPtr.Size * i);
891 stringList.Add(Marshal.PtrToStringAnsi(charArr));
892 Interop.Libc.Free(charArr);
894 Interop.Libc.Free(valuePtr);
900 value = default(IEnumerable<string>);
906 /// Removes the extra data.
908 /// <param name="key">The name of the extra data.</param>
909 /// <exception cref="ArgumentNullException">Thrown when the key is a zero-length string.</exception>
910 /// <exception cref="KeyNotFoundException">Thrown when the key is not found.</exception>
911 /// <exception cref="ArgumentException">Thrown when the key is rejected.</exception>
914 /// AppControl appControl = new AppControl();
915 /// appControl.ExtraData.Remove("myKey");
918 public void Remove(string key)
920 if (string.IsNullOrEmpty(key))
922 throw new ArgumentNullException("key");
924 Interop.AppControl.ErrorCode err = Interop.AppControl.RemoveExtraData(_handle, key);
925 if (err != Interop.AppControl.ErrorCode.None)
929 case Interop.AppControl.ErrorCode.InvalidParameter:
930 throw new ArgumentException("Invalid parameter: key is a zero-length string");
931 case Interop.AppControl.ErrorCode.KeyNotFound:
932 throw new KeyNotFoundException("Key is not found"); ;
933 case Interop.AppControl.ErrorCode.KeyRejected:
934 throw new ArgumentException("Key is rejected: the key is system-defined key.");
936 throw new InvalidOperationException("Error = " + err);
942 /// Counts keys in the extra data.
944 /// <returns>The number of counting keys.</returns>
945 /// <exception cref="InvalidOperationException">Thrown when the key is an invalid parameter.</exception>
948 /// AppControl appControl = new AppControl();
949 /// int numberOfKeys = appControl.ExtraData.Count();
954 return GetKeys().Count();
958 /// Checks whether the extra data associated with the given key is of the collection data type.
960 /// <param name="key">The name of the extra data.</param>
961 /// <returns>If true, the extra data is of the array data type, otherwise false.</returns>
962 /// <exception cref="ArgumentNullException">Thrown when the key is a zero-length string.</exception>
963 /// <exception cref="InvalidOperationException">Thrown when failed to check the key.</exception>
966 /// AppControl appControl = new AppControl();
967 /// bool result = appControl.ExtraData.IsCollection("myKey");
970 public bool IsCollection(string key)
972 if (string.IsNullOrEmpty(key))
974 throw new ArgumentNullException("key");
976 bool isArray = false;
977 Interop.AppControl.ErrorCode err = Interop.AppControl.IsExtraDataArray(_handle, key, out isArray);
978 if (err != Interop.AppControl.ErrorCode.None)
980 throw new InvalidOperationException("Error = " + err);
985 private string GetData(string key)
987 if (string.IsNullOrEmpty(key))
989 throw new ArgumentNullException("key");
991 string value = string.Empty;
992 Interop.AppControl.ErrorCode err = Interop.AppControl.GetExtraData(_handle, key, out value);
993 if (err != Interop.AppControl.ErrorCode.None)
997 case Interop.AppControl.ErrorCode.InvalidParameter:
998 throw new ArgumentException("Invalid parameter: key is a zero-length string");
999 case Interop.AppControl.ErrorCode.KeyNotFound:
1000 throw new KeyNotFoundException("Key is not found"); ;
1001 case Interop.AppControl.ErrorCode.InvalidDataType:
1002 throw new ArgumentException("Invalid data type: value is data collection type");
1003 case Interop.AppControl.ErrorCode.KeyRejected:
1004 throw new ArgumentException("Key is rejected: the key is system-defined key.");
1006 throw new InvalidOperationException("Error = " + err);
1012 private IEnumerable<string> GetDataCollection(string key)
1014 if (string.IsNullOrEmpty(key))
1016 throw new ArgumentNullException("key");
1018 IntPtr valuePtr = IntPtr.Zero;
1020 Interop.AppControl.ErrorCode err = Interop.AppControl.GetExtraDataArray(_handle, key, out valuePtr, out len);
1021 if (err != Interop.AppControl.ErrorCode.None)
1025 case Interop.AppControl.ErrorCode.InvalidParameter:
1026 throw new ArgumentException("Invalid parameter: key is a zero-length string");
1027 case Interop.AppControl.ErrorCode.KeyNotFound:
1028 throw new KeyNotFoundException("Key is not found"); ;
1029 case Interop.AppControl.ErrorCode.InvalidDataType:
1030 throw new ArgumentException("Invalid data type: value is data collection type");
1031 case Interop.AppControl.ErrorCode.KeyRejected:
1032 throw new ArgumentException("Key is rejected: the key is system-defined key.");
1034 throw new InvalidOperationException("Error = " + err);
1038 List<string> valueArray = new List<string>();
1039 if (valuePtr != IntPtr.Zero)
1041 for (int i = 0; i < len; ++i)
1043 IntPtr charArr = Marshal.ReadIntPtr(valuePtr, IntPtr.Size * i);
1044 valueArray.Add(Marshal.PtrToStringAnsi(charArr));
1045 Interop.Libc.Free(charArr);
1047 Interop.Libc.Free(valuePtr);