/// <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"); }