Example #1
0
        /// <include file='doc\DesignerService.uex' path='docs/doc[@for="DesignerService.IVSMDDesignerService.CreateDesigner"]/*' />
        /// <devdoc>
        ///     Creates an instance of the designer using the provided information.
        /// </devdoc>
        IVSMDDesigner IVSMDDesignerService.CreateDesigner(object provider, object designerLoader)
        {
            CodeDomLoader.StartMark();

            IVSMDDesigner designer = null;

            try {
                Debug.WriteLineIf(Switches.DESIGNERSERVICE.TraceVerbose, "DesignerService::CreateDesigner");
                if (!(provider is NativeMethods.IOleServiceProvider))
                {
                    throw new ArgumentException("provider");
                }

                if (!(designerLoader is DesignerLoader))
                {
                    Debug.WriteLineIf(Switches.DESIGNERSERVICE.TraceVerbose, "\tERROR: Code stream does not extend DesignerLoader");
                    throw new Exception(SR.GetString(SR.DESIGNERSERVICEBadDesignerLoader, SR.GetString(SR.DESIGNERSERVICEUnknownName)));
                }

                DocumentManager dm = GetDocumentManager();
                if (dm != null)
                {
                    ServiceProviderArray docProvider = new ServiceProviderArray(new IServiceProvider[] { new DesignerServiceProvider((NativeMethods.IOleServiceProvider)provider), this });
                    designer = (IVSMDDesigner)dm.CreateDesigner((DesignerLoader)designerLoader, docProvider);
                }
            }
            catch (Exception e) {
                Debug.Fail("Failed to create designer", e.ToString());
                throw e;
            }

            CodeDomLoader.EndMark("CreateDesigner");

            return(designer);
        }
        bool ICodeDomDesignerReload.ShouldReloadDesigner(CodeCompileUnit newTree)
        {
            if ((generatedMethods == null || generatedMethods.Count == 0) && (generatedFields == null || generatedFields.Count == 0))
            {
                return(true);
            }

            Hashtable handlers = null;

            // now that we've got a parsed file, walk through each item that we created, and check
            // to see if it changed at all.
            //
            char[] splitChars = new char[] { ':' };

            CodeTypeDeclaration codeType = null;

            if (generatedFields != null)
            {
                foreach (DictionaryEntry de in generatedFields)
                {
                    string hashName = (string)de.Key;

                    CodeMemberField oldField = de.Value as CodeMemberField;

                    if (oldField == null)
                    {
                        continue;
                    }

                    // this string is in the format
                    // <Type Name>:<Field Name>
                    //
                    string[] names = hashName.Split(splitChars);
                    Debug.Assert(names.Length == 2, "Didn't get 2 items from the name hash string '" + hashName + "'");
                    CodeMemberField parsedField = FindMatchingMember(newTree, names[0], oldField, out codeType) as CodeMemberField;

                    if (parsedField == null)
                    {
                        return(true);
                    }
                }
            }

            if (generatedMethods != null)
            {
                foreach (DictionaryEntry de in generatedMethods)
                {
                    string hashName = (string)de.Key;

                    CodeMemberMethod oldMethod = de.Value as CodeMemberMethod;

                    if (oldMethod == null)
                    {
                        continue;
                    }

                    // this string is in the format
                    // <Type Name>:<Method Name>:<Parameter Count>
                    string[] names = hashName.Split(splitChars);
                    Debug.Assert(names.Length == 3, "Didn't get 3 items from the name hash string '" + hashName + "'");

                    CodeDomLoader.StartMark();

                    CodeMemberMethod parsedMethod = FindMatchingMember(newTree, names[0], oldMethod, out codeType) as CodeMemberMethod;

                    CodeDomLoader.EndMark("Reload Parse II:" + oldMethod.Name);

                    // if we have differing statment counts, don't even bother looking at code
                    //
                    if (parsedMethod == null)
                    {
                        return(true);
                    }

                    CodeElement vsCodeElement = parsedMethod.UserData[VsCodeDomParser.VsElementKey] as CodeElement;

                    if (vsCodeElement == null)
                    {
                        return(true);
                    }

                    CodeDomLoader.StartMark();

                    EditPoint startPoint = vsCodeElement.StartPoint.CreateEditPoint();

                    string newCode = startPoint.GetText(vsCodeElement.EndPoint);

                    CodeDomLoader.EndMark("GetCode from VS Element");

                    string oldCode = oldMethod.UserData[GeneratedCodeKey] as string;

                    // okay, let's rock.  if these are different, we need to reload
                    //
                    // sburke: binary compare
                    if (oldCode != newCode)
                    {
                        return(true);
                    }
                    else
                    {
                        // add this to the list of things to generate next time in case we don't regenerate.
                        //
                        DictionaryEntry thisDe = de;
                        thisDe.Value = parsedMethod;
                        parsedMethod.UserData[GeneratedCodeKey] = oldCode;
                        parsedMethod.UserData[VsCodeDomParser.VsGenerateStatementsKey] = VsCodeDomParser.VsGenerateStatementsKey;
                    }

                    // pick up the handlers from this class
                    //
                    if (handlers == null)
                    {
                        handlers = (Hashtable)codeType.UserData[VsCodeDomParser.VbHandlesClausesKey];
                    }
                }
            }

            if (IsVB)
            {
                if ((fullParseHandlers == null) != (handlers == null))
                {
                    return(true);
                }
                if (handlers != null)
                {
                    // first, a quick check to see if our handlers have changed
                    //
                    string[] handlerNames = new string[handlers.Keys.Count];
                    handlers.Keys.CopyTo(handlerNames, 0);
                    string[] lastHandlerHames = new string [fullParseHandlers.Count];
                    fullParseHandlers.Keys.CopyTo(lastHandlerHames, 0);

                    Array.Sort(handlerNames, InvariantComparer.Default);
                    Array.Sort(lastHandlerHames, InvariantComparer.Default);

                    if (lastHandlerHames.Length != handlerNames.Length)
                    {
                        return(true);
                    }

                    for (int i = 0; i < handlerNames.Length; i++)
                    {
                        if (!handlerNames[i].Equals(lastHandlerHames[i]))
                        {
                            return(true);
                        }
                    }

                    // handlers are all the same, make sure they point to the same members
                    //
                    foreach (DictionaryEntry de in fullParseHandlers)
                    {
                        CodeMemberMethod newHandler = handlers[de.Key] as CodeMemberMethod;
                        if (newHandler == null)
                        {
                            return(true);
                        }

                        CodeMemberMethod oldHandler = de.Value as CodeMemberMethod;
                        Debug.Assert(oldHandler != null, "Didn't get an old handler?  How?");
                        if (newHandler.Name != oldHandler.Name ||
                            //newHandler.Attributes != oldHandler.Attributes ||
                            newHandler.ReturnType.BaseType != oldHandler.ReturnType.BaseType)
                        {
                            return(true);
                        }

                        if (newHandler.Parameters.Count == oldHandler.Parameters.Count)
                        {
                            // just to be sure, check the params.
                            for (int i = 0; i < newHandler.Parameters.Count; i++)
                            {
                                if (newHandler.Parameters[i].Type.BaseType != newHandler.Parameters[i].Type.BaseType)
                                {
                                    return(true);
                                }
                            }
                        }
                        else
                        {
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
        /// <include file='doc\VsCodeDomParser.uex' path='docs/doc[@for="VsCodeDomParser.OnMethodPopulateStatements"]/*' />
        /// <devdoc>
        ///     Populate the parameter statement list from a method.  Here is where we invoke the XmlProcessor
        /// </devdoc>
        private void OnMethodPopulateStatements(object sender, EventArgs e)
        {
            CodeMemberMethod codeMethod = (CodeMemberMethod)sender;
            CodeFunction     vsFunction = (CodeFunction)GetVsElementFromCodeObject(codeMethod);

            IMethodXML xmlMethod = null;

            try {
                xmlMethod = (IMethodXML)vsFunction;
            }
            catch {
            }

            if (xmlMethod == null)
            {
                Debug.Fail("Couldn't get IMethodXML for method '" + codeMethod.Name + "'");
                return;
            }

            string xmlCode = null;

            CodeDomLoader.StartMark();

            // get a hold of the XML if possible.
            //
            try {
                xmlMethod.GetXML(ref xmlCode);
            }
            catch (Exception ex) {
                System.Runtime.InteropServices.COMException cex = ex as System.Runtime.InteropServices.COMException;
                throw new Exception(SR.GetString(SR.FailedToParseMethod, vsFunction.Name, ex.Message));
            }
            finally {
                CodeDomLoader.EndMark("GetXML");
                CodeDomLoader.StartMark();
            }

            // pass it along to the processor.
            //
            XmlProcessor.ParseXml(xmlCode, codeMethod.Statements, this.FileName, codeMethod.Name);

            CodeDomLoader.EndMark("XML -> CodeDom Tree");


            // Add the statement count to our user data.  We use this as a quick way to tell if we need to
            // regenerate the contents of a method.
            //
            codeMethod.UserData[VsGenerateStatementsKey] = VsGenerateStatementsKey;

            // clear out the methods that we've generated before...
            //
            provider.ClearGeneratedMembers();

            // now apply any handlers for default events.
            //

            if (provider.IsVB)
            {
                CodeTypeDeclaration codeTypeDecl = (CodeTypeDeclaration)codeMethod.UserData[typeof(CodeTypeDeclaration)];

                if (codeTypeDecl == null)
                {
                    return;
                }

                Hashtable handlers = (Hashtable)codeTypeDecl.UserData[VbHandlesClausesKey];

                // save this so we can compare against it later to see
                // if we need to reload due to a handler change.
                //
                provider.FullParseHandlers = handlers;

                if (handlers == null || handlers.Count == 0)
                {
                    return;
                }
                GetDelegateHookupsFromHandlesClauses(handlers, codeTypeDecl, codeMethod.Statements);
            }
        }
        private void GetDelegateHookupsFromHandlesClauses(Hashtable handlers, CodeTypeDeclaration codeTypeDecl, CodeStatementCollection statements)
        {
            CodeDomLoader.StartMark();

            // unfortunately, we have to essentially parse the code to find the objects
            // that we are instantiating to get their types and names
            //
            // then we get the default event for each type, and then we walk through our list
            // of handlers and add statement hookups for the default ones.
            //
            // why do we go through all this work?  because we need to know which ones are set by
            // parse time or when we double click on the same control, we'll think we have to add another handler.
            //

            Hashtable objs = new Hashtable();

            foreach (CodeTypeMember member in codeTypeDecl.Members)
            {
                CodeMemberField field = member as CodeMemberField;
                if (field != null)
                {
                    objs[field.Name] = field.Type.BaseType;
                }
            }


            // and add our base type...
            //
            objs["MyBase"] = codeTypeDecl.BaseTypes[0].BaseType;

            // again by name because Visual Basic keeps switching back and forth...
            //
            objs[codeTypeDecl.Name] = codeTypeDecl.BaseTypes[0].BaseType;

            // now we have all the created objects, so we walk through the
            // handlers we've found and see which ones are default handlers for those objects.
            //
            ITypeResolutionService typeLoader = provider.TypeLoader;
            Type baseType = null;

            if (typeLoader != null)
            {
                // now walk through them, checking each to see if we're on a default event
                //

                foreach (DictionaryEntry de in handlers)
                {
                    // get the handler and and the data for this field
                    //
                    string handler   = (string)de.Key;
                    int    dot       = handler.IndexOf('.');
                    string fieldName = handler.Substring(0, dot);

                    object objInfo   = objs[fieldName];
                    Type   fieldType = null;

                    if (objInfo == null)
                    {
                        // this means this thing isn't an IComponent...try to reflect against the base type
                        //
                        if (baseType == null)
                        {
                            baseType = typeLoader.GetType(codeTypeDecl.BaseTypes[0].BaseType, false);
                        }
                        if (baseType != null)
                        {
                            // because of the wonderful magicalness of VB, there isn't actually a field called "button1", it's a
                            // property. so we get to walk all the fields, looking for one who has the neat
                            // little Accessed through property attribute that matches the name of this member.
                            //
                            foreach (FieldInfo field in baseType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
                            {
                                if (field.Name == fieldName)
                                {
                                    fieldType = field.FieldType;
                                    break;
                                }

                                object[] fieldAttrs = field.GetCustomAttributes(typeof(AccessedThroughPropertyAttribute), false);
                                if (fieldAttrs != null && fieldAttrs.Length > 0)
                                {
                                    AccessedThroughPropertyAttribute propAttr = (AccessedThroughPropertyAttribute)fieldAttrs[0];
                                    // does the property name on the attribute match what we're looking for?
                                    //
                                    if (propAttr.PropertyName == fieldName)
                                    {
                                        PropertyInfo fieldProp = baseType.GetProperty(propAttr.PropertyName,
                                                                                      BindingFlags.Instance |
                                                                                      BindingFlags.Public |
                                                                                      BindingFlags.NonPublic);

                                        // now go find the property and get its value
                                        //
                                        if (fieldProp != null)
                                        {
                                            MethodInfo getMethod = fieldProp.GetGetMethod(true);
                                            if (getMethod != null && !getMethod.IsPrivate)
                                            {
                                                fieldType = fieldProp.PropertyType;
                                            }
                                            break;
                                        }
                                    }
                                }
                            }

                            if (fieldType != null)
                            {
                                objs[fieldName] = fieldType;
                                objInfo         = fieldType;
                            }
                            else
                            {
                                // flag failure of this type so we
                                // don't check again.
                                //
                                objs[fieldName] = false;
                                objInfo         = false;
                                continue;
                            }
                        }
                    }

                    if (objInfo is string)
                    {
                        // it's the type name, get the default handler from the TypeDescriptor
                        //
                        Type t = typeLoader.GetType((string)objInfo, false);

                        if (t != null)
                        {
                            objs[fieldName] = t;
                            fieldType       = t;
                        }
                    }
                    else if (objInfo is Type)
                    {
                        // just grab the handler
                        //
                        fieldType = (Type)objInfo;
                    }
                    else if (objInfo is bool)
                    {
                        // we've failed here before, just give up!
                        //
                        continue;
                    }
                    else
                    {
                        // errr, how'd we get here?
                        //
                        Debug.Fail("Why does the handler data have a '" + objInfo.GetType().FullName + "'?");
                        continue;
                    }

                    // now that we have a default event, see if the
                    // handler we're currently on, say "button1.Click" matches
                    // what the handles clause for this component would look like.
                    //

                    if (fieldType != null)
                    {
                        string eventName = handler.Substring(dot + 1);

                        // Make sure this is a valid event for this type
                        EventDescriptor eventDesc = TypeDescriptor.GetEvents(fieldType)[eventName];

                        // (bug 120608) if we got null, we may be hooking up a private interface member. Try to find it.
                        //
                        if (eventDesc == null)
                        {
                            foreach (Type interfaceType in fieldType.GetInterfaces())
                            {
                                EventInfo eventInfo = interfaceType.GetEvent(eventName);
                                if (eventInfo != null)
                                {
                                    eventDesc = TypeDescriptor.CreateEvent(interfaceType, eventName, eventInfo.EventHandlerType);
                                    break;
                                }
                            }
                        }

                        Debug.Assert(eventDesc != null, "Handles clause '" + handler + "' found, but type '" + fieldType.FullName + "' does not have an event '" + eventName + "'");

                        if (eventDesc != null)
                        {
                            CodeMemberMethod method          = de.Value as CodeMemberMethod;
                            CodeStatement    attachStatement = CreateEventAttachStatement(fieldName == "MyBase" ? null : fieldName, eventDesc, method.Name);
                            attachStatement.UserData[CodeDomXmlProcessor.KeyXmlParsedStatement] = CodeDomXmlProcessor.KeyXmlParsedStatement;
                            statements.Add(attachStatement);
                        }
                    }
                }
            }

            CodeDomLoader.EndMark("Handles clauses to delegate hookups");
        }