public void GetColorEx(int color_id, out int color_class_id, ref double[] v)
        {
            PhotoshopTypeLibrary.IActionDescriptor desc2;
            CheckEnum(color_id, (int)con.phKeyForegroundColor, (int)con.phKeyBackgroundColor);

            IActionDescriptor desc = get_descriptor_to_object_property_by_index((int)con.phClassApplication, -1, color_id);

            int actual_color_class_id;

            desc.GetObject((int)con.phKeyForegroundColor, out actual_color_class_id, out desc2);



            if (actual_color_class_id == (int)con.phClassRGBColor)
            {
                color_class_id = (int)con.phClassRGBColor;
                v[0]           = (double)get_value_from_descriptor(desc2, (int)con.phKeyRed);
                v[1]           = (double)get_value_from_descriptor(desc2, (int)con.phKeyGreen);
                v[2]           = (double)get_value_from_descriptor(desc2, (int)con.phKeyBlue);
                v[3]           = 0;
            }
            else
            {
                string msg = string.Format("Did not understand color type returned");
                var    e   = new PhotoshoProxyError(msg);
                throw e;
            }
        }
        public void SetColorEx(int color_id, int color_class, double[] v)
        {
            var Desc2 = this.m_app.MakeDescriptor();

            if (color_class == (int)con.phClassHSBColor)
            {
                Desc2.PutUnitDouble((int)con.phKeyHue, (int)con.phUnitAngle, v[0]);
                Desc2.PutDouble((int)con.phKeySaturation, v[1]);
                Desc2.PutDouble((int)con.phKeyBrightness, v[2]);
            }
            else if (color_class == (int)con.phClassRGBColor)
            {
                Desc2.PutDouble((int)con.phKeyRed, v[0]);
                Desc2.PutDouble((int)con.phKeyGrain, v[1]);
                Desc2.PutDouble((int)con.phKeyBlue, v[2]);
            }
            else if (color_class == (int)con.phClassLabColor)
            {
                Desc2.PutDouble((int)con.phKeyLuminance, v[0]);
                Desc2.PutDouble((int)con.phKeyA, v[1]);
                Desc2.PutDouble((int)con.phKeyB, v[2]);
            }
            else if (color_class == (int)con.phClassCMYKColor)
            {
                Desc2.PutDouble((int)con.phKeyCyan, v[0]);
                Desc2.PutDouble((int)con.phKeyMagenta, v[1]);
                Desc2.PutDouble((int)con.phKeyYellow, v[2]);
                Desc2.PutDouble((int)con.phKeyBlack, v[3]);
            }
            else
            {
                var e = new PhotoshoProxyError("Improper Color Class");
                throw e;
            }

            var Ref1 = this.m_app.MakeReference();

            Ref1.PutProperty((int)con.phClassColor, color_id);

            var Desc1 = this.m_app.MakeDescriptor();

            Desc1.PutReference((int)con.phKeyNull, Ref1);
            Desc1.PutObject((int)con.phKeyTo, color_class, Desc2);


            // ----------------------------------------
            // Play the event
            // ----------------------------------------
            PlayEvent((int)con.phEventSet, Desc1, (int)con.phDialogSilent, PlayBehavior.checkresult);
        }
        public void CheckEnum(string v, params string[] enum_range)
        {
            bool found = false;

            foreach (string enum_value in enum_range)
            {
                if (v == enum_value)
                {
                    found = true;
                    break;
                }
            }

            if (!found)
            {
                PhotoshoProxyError e = new PhotoshoProxyError("Not in range");
                throw (e);
            }
        }
        /*
         *
         *
         * public  void XPutRectangleIntoDescriptor( PhotoshopTypeLibrary.IActionDescriptor d, double top, double left, double bottom, double right )
         * {
         *  int unit = (int)con.phUnitDistance;
         *  d.PutUnitDouble( (int)con.phKeyTop, unit, top );
         *  d.PutUnitDouble( (int)con.phKeyLeft, unit, left );
         *  d.PutUnitDouble( (int)con.phKeyBottom, unit, bottom );
         *  d.PutUnitDouble( (int)con.phKeyRight, unit, right );
         * }
         *
         * public  void XPutRectangleIntoDescriptorEx( PhotoshopTypeLibrary.IActionDescriptor d, double top, double left, double bottom, double right, int convert )
         * {
         *  int unit = (int)con.phUnitDistance;
         *
         *  if ( convert==1 )
         *  {
         *      // the input is pixels, convert to points
         *      top = pixels_to_points( top );
         *      left = pixels_to_points( left );
         *      bottom = pixels_to_points( bottom );
         *      right = pixels_to_points( right );
         *  }
         *  else
         *  {
         *      // convert convert the points
         *  }
         *
         *  d.PutUnitDouble( (int)con.phKeyTop, unit, top );
         *  d.PutUnitDouble( (int)con.phKeyLeft, unit, left );
         *  d.PutUnitDouble( (int)con.phKeyBottom, unit, bottom );
         *  d.PutUnitDouble( (int)con.phKeyRight, unit, right );
         * }
         *
         *
         *
         */



        public void CheckEnumEx(int v, int[] enum_range)
        {
            bool found = false;

            foreach (int enum_value in enum_range)
            {
                if (v == enum_value)
                {
                    found = true;
                    break;
                }
            }

            if (!found)
            {
                PhotoshoProxyError e = new PhotoshoProxyError("Not in range");
                throw (e);
            }
        }
        public int get_count_from_object_collection(int object_id)
        {
            int count = 0;

            if (object_id == (int)PSConstants.phClassDocument)
            {
                count = (int)get_value_from_object((int)PSConstants.phClassApplication, -1, (int)PSConstants.phKeyNumberOfDocuments);
            }
            else if (object_id == (int)PSConstants.phClassLayer)
            {
                count = (int)get_value_from_object((int)PSConstants.phClassDocument, -1, (int)PSConstants.phKeyNumberOfLayers);
            }
            else
            {
                string msg = string.Format("Invalid object_id {0},{1}: only documents and layers are supported", object_id, IDToStr(object_id));
                var    e   = new PhotoshoProxyError(msg);
                throw e;
            }
            return(count);
        }
        public void OpenDocument(string filename)
        {
            if (IsFileLoaded(filename))
            {
                string msg = string.Format("The file \"{0}\" is already open.", filename);
                var    e   = new PhotoshoProxyError(msg);
                throw e;
            }

            CheckFileExists(filename);

            // Desc1
            var Desc1 = this.m_app.MakeDescriptor();

            Desc1.PutPath((int)con.phKeyNull, filename);

            int old_count = GetDocumentCount();

            // Play the event in photoshop
            PlayEvent((int)con.phEventOpen, Desc1, (int)con.phDialogSilent, PlayBehavior.checkresult);

            //DocumentAPI.CheckDocumentCount(old_count + 1);
        }
        public Object get_value_from_descriptor(PhotoshopTypeLibrary.IActionDescriptor desc, int prop_id)
        {
            ///
            ///<summary>
            ///
            /// Given a descriptor and a propid, will return an Object containing
            /// the value
            ///
            /// If there is no prop_id, then returns null
            ///
            /// Workitem: this should really return an exception if the property doesn't
            /// exist or it should return an additional error code.
            ///
            ///</summary>
            ///


            if (!desc_has_key(desc, prop_id))
            {
                // If the descriptor does not contain the key, return null
                return(null);
            }

            // Stores the object being returned
            Object o = null;

            // Determine the type of the object
            int type = 0;

            type = get_type_from_descriptor(desc, prop_id);

            if (type == (int)PSConstants.phTypeChar)
            {
                string v;
                desc.GetString(prop_id, out v);
                o = (string)v;
            }
            else if (type == (int)PSConstants.phTypeInteger)
            {
                int v;
                desc.GetInteger(prop_id, out v);
                o = v;
            }
            else if (type == (int)PSConstants.phTypeFloat)
            {
                double v;
                desc.GetDouble(prop_id, out v);
                o = v;
            }
            else if (type == (int)PSConstants.phTypeBoolean)
            {
                int v;
                desc.GetBoolean(prop_id, out v);
                o = v;
            }
            else if (type == (int)PSConstants.phTypeUnitFloat)
            {
                // WORKITEM: Return an array instead
                int    unit_id;
                double v;
                desc.GetUnitDouble(prop_id, out unit_id, out v);
                o = v;
            }
            else if (type == (int)PSConstants.phTypeEnumerated)
            {
                // WORKITEM: Return an array instead
                int enum_type;
                int enum_value;
                desc.GetEnumerated(prop_id, out enum_type, out enum_value);
                o = enum_value;
            }
            else if (type == (int)PSConstants.phTypeObject)
            {
                // WORKITEM: Return an array instead
                int class_id;
                PhotoshopTypeLibrary.IActionDescriptor v;
                desc.GetObject(prop_id, out class_id, out v);
                o = v;
            }
            else if (type == (int)PSConstants.phTypePath)
            {
                string v;
                desc.GetPath(prop_id, out v);
                o = v;
            }
            else
            {
                string type_name = GetNameFromTypeID(type);
                string msg       = "Unsupported type " + type_name;
                var    e         = new PhotoshoProxyError(msg);
                throw (e);
            }


            return(o);
        }
        public void PlayEvent(int event_id, PhotoshopTypeLibrary.IActionDescriptor parameter_desc, int show_ui, PlayBehavior action)
        {
            /*event_id - the event to play
             * parameter_descriptor - a descriptor containing the parameters for the event
             * dialog_options - whether to show UI or not
             * action - the kind of error checking to use. Possilble values are checkresult,checknonresult, and checknone
             *
             *
             * checkresult and checknonresult will cause
             * ExtensionError exceptions to be thrown if Photoshop
             * says there is an error. Regardless of the value used
             * for action, a number of ExtensionError exceptions may
             * be thrown.
             *
             */

            string event_id_str = GetNameFromEventID(event_id);

            //self.log.Header( "Play %s (0x%d) " % (event_id_str, event_id ) )


            PhotoshopTypeLibrary.IActionDescriptor result_desc = m_control.Play(event_id, parameter_desc, show_ui);

            // phKeyMessage may be present and contain more information about the event
            // store the value in msg
            string msg = null;


            if (result_desc != null)
            {
                object msg_o = get_value_from_descriptor(result_desc, (int)PSConstants.phKeyMessage);
                msg = (string)msg_o;;

                dump_descriptor(result_desc, 0);
            }

            bool success = false;

            // Depending on the action there are different criterias for success
            if (action == PlayBehavior.checkresult)
            {
                // Succes is one of the following:
                // - Play() did not return a descriptor
                // - Play() did return a descriptor and that did not contain phKeyMessage
                success = ((result_desc == null) || ((result_desc != null) && (msg == null)));
            }
            else if (action == PlayBehavior.checknonresult)
            {
                // Success is:
                // - Play() did return a descriptor and there is a message
                success = ((result_desc != null) && (msg != null));
            }
            else
            {
                // action == self.checknone ) :
                // Whatever happened is success
                // checknone is for temporary code, callers should end up using checkresult or checknonresult
                success = true;
            }

            if (!success)
            {
                string error_msg = "Photoshop ExtensionError: Failure on Event " + event_id_str;
                if (msg != null)
                {
                    error_msg += msg;
                    var e = new PhotoshoProxyError(error_msg);
                    throw (e);
                }
            }

            //self.log.Header( "PLAY" )
            //self.DumpDescriptor( result_desc, 0)
        }